Docker RUN command in exec form not working - docker

I'm building a docker image based on Alpine.
FROM alpine
RUN apk update \
&& apk add lighttpd \
&& rm -rf /var/cache/apk/*
ENV COLOR red
COPY ./index.html /var/www/localhost/htdocs
RUN /bin/ash -c 'echo abcd'
#working
RUN /bin/ash -c "echo $COLOR; sed -i -e 's/red/\$COLOR/g' /var/www/localhost/htdocs/index.html; cat /var/www/localhost/htdocs/index.html;"
#not working
# RUN ["sh", "-c", "echo $COLOR; sed -i -e 's/red/\$COLOR/g' /var/www/localhost/htdocs/index.html; cat /var/www/localhost/htdocs/index.html;"]
CMD ["lighttpd","-D","-f","/etc/lighttpd/lighttpd.conf"]
When I run in shell form it's working fine, but when I run in exec form it's giving
/bin/sh: [sh,: not found
I tried using bin/sh, sh, bin/ash, ash. Same error for all of them.

Shell is responsible for expanding variables, but only variable in double quotes will be expanded.
Your error comes from wrong \ before $COLOR, in fact it did no meaning for you to get the value from shell, the correct way is next:
RUN ["sh", "-c", "echo $COLOR; sed -i -e \"s/red/$COLOR/g\" /var/www/localhost/htdocs/index.html; cat /var/www/localhost/htdocs/index.html;"]
A minimal example to show the effect, FYI:
Dockerfile:
FROM alpine
ENV COLOR rednew
RUN echo "red" > /tmp/index.html
RUN ["sh", "-c", "sed -i -e \"s/red/$COLOR/g\" /tmp/index.html; cat /tmp/index.html;"]
Result:
$ docker build -t abc:1 . --no-cache
Sending build context to Docker daemon 5.632kB
Step 1/4 : FROM alpine
---> 28f6e2705743
Step 2/4 : ENV COLOR rednew
---> Running in 05c43146fab0
Removing intermediate container 05c43146fab0
---> 28ea1434e626
Step 3/4 : RUN echo "red" > /tmp/index.html
---> Running in 2c8fbbc5fd10
Removing intermediate container 2c8fbbc5fd10
---> f884892ad8c4
Step 4/4 : RUN ["sh", "-c", "sed -i -e \"s/red/$COLOR/g\" /tmp/index.html; cat /tmp/index.html;"]
---> Running in 6930b3d03438
rednew
Removing intermediate container 6930b3d03438
---> b770475672cc
Successfully built b770475672cc
Successfully tagged abc:1

I've been using Docker for a few years and I did not know (until your question) that there are shell|exec forms for RUN ;-)
The issue is that your command includes environment variables ($COLOR) and there's no substituation|evaluation with the exec form.
See:
https://docs.docker.com/engine/reference/builder/#run
"Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen"

Related

How to create directory in docker image?

I tried mkdir -p it didn't work.
I have the following Dockerfile:
FROM jenkins/jenkins:2.363-jdk11
ENV PLUGIN_DIR /var/jenkins_home/plugins
RUN echo $PLUGIN_DIR
RUN mkdir -p $PLUGIN_DIR
RUN ls $PLUGIN_DIR
# WORKDIR /var/jenkins_home/plugins # Can't use this, as it changes the permission to root
# which breaks the plugin installation step
# # COPY plugins.txt /usr/share/jenkins/plugins.txt
# # RUN jenkins-plugin-cli -f /usr/share/jenkins/plugins.txt --verbose
#
#
# # disable the setup wizard as we will set up jenkins as code
# ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false
#
# ENV CASC_JENKINS_CONFIG /configs/jcasc.yaml
The build fails!
docker build -t jenkins:test.1 .
Sending build context to Docker daemon 51.2kB
Step 1/5 : FROM jenkins/jenkins:2.363-jdk11
---> 90ff7cc5bfd1
Step 2/5 : ENV PLUGIN_DIR /var/jenkins_home/plugins
---> Using cache
---> 0a158958aab0
Step 3/5 : RUN echo $PLUGIN_DIR
---> Running in ce56ef9146fc
/var/jenkins_home/plugins
Step 4/5 : RUN mkdir -p $PLUGIN_DIR
---> Using cache
---> dbc4e12b9808
Step 5/5 : RUN ls $PLUGIN_DIR
---> Running in 9a0edb027862
I need this because Jenkins deprecated old plugin installation method. The new cli installs plugins to /usr/share/jenkins/ref/plugins instead.
Also:
+$ docker run -it --rm --entrypoint /bin/bash --name jenkins jenkins:test.1
jenkins#7ad71925f638:/$ ls /var/jenkins_home/
jenkins#7ad71925f638:/$
The official Jenkins image on dockerhub declare VOLUME /var/jenkins_home, and subsequent changes to that directory (even in derived images) are discarded.
To workaround, you can execute mkdir as ENTRYPOINT.
And to verify that its working you can add an sleep to enter into the container and verify. It work !.
FROM jenkins/jenkins:2.363-jdk11
ENV PLUGIN_DIR /var/jenkins_home/plugins
RUN echo $PLUGIN_DIR
USER root
RUN echo "#!/bin/sh \n mkdir -pv $PLUGIN_DIR && sleep inf" > ./mkdir.sh
RUN chmod a+x ./mkdir.sh
USER jenkins
ENTRYPOINT [ "/bin/sh", "-c", "./mkdir.sh"]
after
docker build . -t <image_name>
docker run -d <image_name> --name <container_name>
docker exec -it <container_name> bash
and you will see your directory
Sources:
https://forums.docker.com/t/simple-mkdir-p-not-working/42179
https://hub.docker.com/_/jenkins

Building a Linux Docker image on Windows 10: "exec format error"

I am using as a base, the following image: https://github.com/Kaggle/docker-python/blob/main/Dockerfile.
Here is my Dockerfile:
FROM kaggle/python
RUN ["chmod", "+x", "/opt/conda/etc/profile.d/conda.sh"]
SHELL ["/bin/bash", "--login", "-c" ]
RUN ["/opt/conda/etc/profile.d/conda.sh"]
ENTRYPOINT [ "/usr/bin/env" ]
RUN ["exec '$#'"]
RUN ["bash"]
I am running the command: docker build -t kaggle/no-jupyter .
At line 4 I get the error:
> [3/7] RUN ["/opt/conda/etc/profile.d/conda.sh"]:
#6 0.263 standard_init_linux.go:228: exec user process caused: exec format error
Here is a link to the conda.sh file: https://pastebin.com/Epu4d7Nq
I read that this might be because I am building a Linux image on Windows10...Any ideas?
See RUN Syntax:
RUN
RUN has 2 forms:
RUN (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
RUN ["executable", "param1", "param2"] (exec form)
What you choose is exec form which won't run in a shell, so your /opt/conda/etc/profile.d/conda.sh surely fails.
To fix it you need to change to:
RUN ["bash", "/opt/conda/etc/profile.d/conda.sh"]
Or just use shell form:
RUN /opt/conda/etc/profile.d/conda.sh
Minimal example:
run.sh:
echo "hello"
Dockerfile:
FROM ubuntu:16.04
COPY run.sh /
RUN ["bash", "/run.sh"]
Execution:
$ docker build -t abc:1 . --no-cache
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM ubuntu:16.04
---> 065cf14a189c
Step 2/3 : COPY run.sh /
---> 8741ec438afd
Step 3/3 : RUN ["bash", "/run.sh"]
---> Running in 5e6754c79bc1
hello
Removing intermediate container 5e6754c79bc1
---> 3edd77959de4
Successfully built 3edd77959de4
Successfully tagged abc:1
AND, if not use bash, it will show error likes next:
Dockerfile:
FROM ubuntu:16.04
COPY run.sh /
RUN ["/run.sh"]
Execution:
$ docker build -t abc:1 . --no-cache
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM ubuntu:16.04
---> 065cf14a189c
Step 2/3 : COPY run.sh /
---> 82412a703847
Step 3/3 : RUN ["/run.sh"]
---> Running in 2a2b00f966c7
standard_init_linux.go:211: exec user process caused "exec format error"
The command '/run.sh' returned a non-zero code: 1

Docker: Cannot execute binary file

I can't run any binary in my docker container.
Dockerfile:
FROM ubuntu:eoan AS compiler-build
RUN apt-get update && \
dpkg --add-architecture i386 && \
apt-get install -y gcc \
gcc-multilib \
make \
cmake \
git \
python3.8 \
bash
WORKDIR /home
ADD . /home/pawn
RUN mkdir build
WORKDIR /home/build
ENTRYPOINT ["/bin/bash"]
CMD ["/bin/bash"]
I can't even use file builtin:
[root#LAPTOP-EJ5BH6DJ compiler]:~/dev/private/SAMP/compiler (v13.11.0) (master) dc run compiler file bash
/usr/bin/file: /usr/bin/file: cannot execute binary file
From this forum thread:
This error occurs when you use a shell in your entrypoint without the "-c" argument
So, if you change your Dockerfile to end with
ENTRYPOINT [ "/bin/bash", "-l", "-c" ]
then you can run binary files.
Note the purpose of the options for /bin/bash, from the manpage:
-l: Make bash act as if it had been invoked as a login shell
-c: If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.
Additionally, this article is a worthwhile read on how to use both ENTRYPOINT and CMD together, and what their differences are.
EDIT: Here's another article that goes into a trivial (but clearer than the first article) example using the echo shell builtin.
EDIT: Here's an adaptation of the trivial example from the second article I linked:
FROM ubuntu
ENTRYPOINT [ "/bin/bash", "-l", "-c" ]
CMD [ "ls" ]
$ docker build -t test .
$ docker run --rm test
bin
boot
...
var
$ docker run --rm test "ls etc"
adduser.conf
alternatives
apt
...
update-motd.d
xattr.conf
Note the " around ls /etc. Without the quotes, the argument /etc doesn't seem to be passed to the ls command as I might expect.
Entrypoint can't point to /bin/bash it seems. Removing
ENTRYPOINT ["/bin/bash"] is enough to make it work.
I hit the same error. Unlike the other answers, my error was related to my docker run parameters:
# failed
docker run -it $(pwd | xargs basename):latest bash
# worked
docker run -it $(pwd | xargs basename):latest
I didn't need to add bash as I already had this in my Dockerfile:
ENTRYPOINT ["/bin/bash"]
There are times when we don't have control over the image's Dockerfile but it's original entrypoint has an issue.
We could overwrite it's entrypoint to debug issues:
# example
docker run --rm \
--entrypoint /bin/bash \
-it apache/spark-py:v3.3.0

error mxnet build inside Docker image

When I tried to build mxnet inside a Docker image, I got the following message :
Step 14/16 : RUN ["/bin/bash", "-c", "cd /workspace/Project/mxnet"]
---> Running in c9337d66ee5e /workspace/Project/mxnet
Removing intermediate container c9337d66ee5e
---> b92ad26e0218 Step 15/16 : RUN ["/bin/bash", "-c", "make"]
---> Running in 653a66e430b2 make:
*** No targets specified and no makefile found.
Stop. The command '/bin/bash -c make' returned a non-zero code: 2
any suggestion?
The issue at
Step 15/16 : RUN ["/bin/bash", "-c", "make"]
[…] The command '/bin/bash -c make' returned a non-zero code: 2
probably comes from the fact you run beforehand this command:
Step 14/16 : RUN ["/bin/bash", "-c", "cd /workspace/Project/mxnet"]
which is a typical bug pattern in Docker.
To sum up, each Docker RUN command is run in a subshell, so that if you do
RUN ["/bin/bash", "-c", "cd /workspace/Project/mxnet"]
RUN other commands
The other commands won't be affected by the directory change.
To solve this, you can either:
replace both lines with
RUN cd /workspace/Project/mxnet && other commands
or (solution preferred) replace both lines with
WORKDIR /workspace/Project/mxnet
RUN other commands
Solution 2 is more idiomatic, and note that
WORKDIR /dir
RUN some command
can be semantically seen as the equivalent of the command
mkdir -p /dir && cd /dir && /bin/sh -c "some command"

Dockerfile: create ENV variable that a USER can see?

Is there a way to set an ENV variable for a custom USER in a docker file?
I am trying the following:
FROM some_repo/my_base_image
ENV FOO_VAR bar_value
USER webapp
# ... continued (not important)
But my "webapp" user can not see the "FOO_VAR" variable. HOWEVER, my root user CAN.
Any help would be appreciated.
Any user can see the environment variables:
$ cat Dockerfile
FROM debian
ENV foo bar
RUN groupadd -r am && useradd -r -g am am
USER am
$ docker build -t test .
...
$ docker run test bash -c 'echo $foo'
bar
So that's not what the problem is. It may be that your process forked a new environment, but I can't be sure as you haven't shared how you're checking the value.
If you switch user context using su within the dockerfile's ENTRYPOINT, CMD or docker exec ... using the form below you enter a new shell process for the given username that does not persist your original environment variables provided by the ENV targets through dockerfile, docker-compose yaml, or docker run -e ...
> su - username -c "run a process"
To avoid this behavior simply remove the dash - from the call like so:
> su username -c "run a process"
Your assigned docker environment variables will now persist.
For future reference, this also holds true within the Dockerfile (and not just for any container's user during run-time):
$ cat Dockerfile
FROM library/debian:9.5
ENV FOO="BAR"
RUN groupadd -r testuser && useradd -r -g testuser testuser
RUN mkdir -p /home/testuser && chown -R testuser /home/testuser
RUN echo "${FOO}" && echo "meh.${FOO}.blah"
USER testuser
RUN echo "${FOO}" && echo "meh.${FOO}.blah" | tee -a ~/test.xt
And docker build:
$ docker build -t test .
Sending build context to Docker daemon 2.048kB
Step 1/7 : FROM library/debian:9.5
---> be2868bebaba
Step 2/7 : ENV FOO="BAR"
---> Running in f2cd5ecca056
Removing intermediate container f2cd5ecca056
---> f6f7b3f26cad
Step 3/7 : RUN groupadd -r testuser && useradd -r -g testuser testuser
---> Running in ab9c0726cc1e
Removing intermediate container ab9c0726cc1e
---> dc9f2a35fb09
Step 4/7 : RUN mkdir -p /home/testuser && chown -R testuser /home/testuser
---> Running in 108b1c03323d
Removing intermediate container 108b1c03323d
---> 4a63e70fc886
Step 5/7 : RUN echo "${FOO}" && echo "meh.${FOO}.blah"
---> Running in 9dcdd6b73e7d
BAR
meh.BAR.blah
Removing intermediate container 9dcdd6b73e7d
---> c33504cadc37
Step 6/7 : USER testuser
---> Running in 596b0588dde6
Removing intermediate container 596b0588dde6
---> 075e2c861021
Step 7/7 : RUN echo "${FOO}" && echo "meh.${FOO}.blah" | tee -a ~/test.xt
---> Running in fb2648d8c120
BAR
meh.BAR.blah
Removing intermediate container fb2648d8c120
---> c7c1c69e200f
Successfully built c7c1c69e200f
Successfully tagged test:latest
(Yet for some reason it doesn't work for me in my own project, when I use the variables as a part of a curl URL target...)
here's what worked for me after browsing around the web looking for the answer:
in the dockerfile
...
RUN apt install sudo -y
ENV MY_VAR="some value"
...
now inside the container (or in my case the script i wrote to run inide it):
sudo -E -u my_user env # <- switch here to whatever command you want to execute
-E stands for preserve-env which means the env vars of the root user will be passed to my_user
heres my reference:
https://dev.to/pfreitag/passing-environment-variables-with-sudo-1ej6

Resources