SantaXL
SantaXL

Reputation: 674

Docker CMD - when should shell form be used?

Dockerfile - best practices says that

CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…]

in which case shell form should be used?

Upvotes: 4

Views: 2954

Answers (3)

Z4-tier
Z4-tier

Reputation: 7988

Shell form will invoke a command shell and do the usual command processing that the shell typically handles (like substitution of environment variables such as $HOME). The exec form doesn't do that.

That is closely related to the SHELL directive.

You can have multiple SHELL commands in the Dockerfile, but only one CMD. CMD is used to specify what the container should run when it starts. The SHELL directive will overwrite the default shell that is used by the shell-form of various commands (RUN, CMD, ENTRYPOINT).

Using this Dockerfile illustrates this better than I could explain it:

FROM python:3.6
RUN echo $PATH
SHELL ["/bin/bash" ,"-c"]
RUN echo $PATH
RUN ["echo", "$PATH"]
COPY run.sh /run.sh

ENTRYPOINT ["/run.sh"]

Will result in this when running docker build:

$ docker build .

Sending build context to Docker daemon   5.12kB
Step 1/7 : FROM python:3.6
 ---> 5bf410ee7bb2
Step 2/7 : RUN echo $PATH
 ---> Running in 3a08d7c4450c
/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Removing intermediate container 3a08d7c4450c
 ---> 85b4da5d8e5d
Step 3/7 : SHELL ["/bin/bash" ,"-c"]
 ---> Running in da1b90ac14f2
Removing intermediate container da1b90ac14f2
 ---> ed747f0862a6
Step 4/7 : RUN echo $PATH
 ---> Running in 5c6a86e133ff
/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Removing intermediate container 5c6a86e133ff
 ---> 8ec42f23d390
Step 5/7 : RUN ["echo", "$PATH"]
 ---> Running in cc0650a6d8e8
$PATH
Removing intermediate container cc0650a6d8e8
 ---> 8b11432adb3a
Step 6/7 : COPY run.sh /run.sh
 ---> a168c58738e7
Step 7/7 : ENTRYPOINT ["/run.sh"]
 ---> Running in f9e28048d139
Removing intermediate container f9e28048d139
 ---> d20920ea562c
Successfully built d20920ea562c

Notice that when it ran the shell mode commands (using both the default shell and bash), $PATH was expanded, but not when run using exec mode.

Upvotes: 4

David Maze
David Maze

Reputation: 159830

For CMD, you need shell form only if you need functionality that’s only provided in a shell — if your CMD includes environment variable references $ARG, multiple commands a && b, pipelines | tee ..., or redirections 2>&1. If you have an especially complex CMD like this it might be a better practice to move it to a shell script (that you can independently test outside of Docker) and have your default CMD just be to invoke the script.

RUN technically has the same considerations. It’s very common to run multiple commands in the same RUN instruction, though, and this requires shell form. Almost every RUN line I’ve ever seen uses the shell form.

ENTRYPOINT should always be the JSON-array form. Remember that the entrypoint gets passed the command as arguments; if you use the shell form it effectively causes these arguments to be ignored. Again, if you need to do complex things in your ENTRYPOINT (including exec "$@" to run the command), split it into a separate shell script and invoke it using JSON-array syntax.

Upvotes: 3

Itamar Turner-Trauring
Itamar Turner-Trauring

Reputation: 3900

Pretty much never; if you need a shell command, you can just call a script with parenthesis format (CMD ["bash", "myscript.sh"]). The problem with shell form is that it breaks shutdown: https://hynek.me/articles/docker-signals/

Upvotes: 2

Related Questions