Let’s start with a simple command:
echo hello world
Now have a look at the following combinations of dockers CMD
and ENTRYPOINT
:
FROM alpine AS example_0
ENTRYPOINT ["echo", "Hello"]
CMD ["World"]
FROM alpine AS example_1
ENTRYPOINT ["echo", "Hello", "World"]
FROM alpine AS example_2
CMD ["echo", "Hello", "World"]
FROM alpine AS example_3
ENTRYPOINT echo "Hello ${2:1:-1}"
CMD "World"
FROM alpine AS example_4
ENTRYPOINT echo "Hello World"
FROM alpine AS example_5
CMD echo "Hello World"
If I run these images, they will all output Hello World
. Don’t believe me? Use the docker-compose in the gist and try it out for yourself. After running docker compose up
you will see the following:
I always need to remember the differences between these permutations and get confused about the correct choice. So, let’s demystify this madness, break down some key choices, and identify sensible defaults.
Shell vs Exec
Links
- Docker docs
Shell Style
Shell style commands run in a sub process, the syntax is more liberal. The following is an example of the shell syntax:
ENTRYPOINT echo "Hello ${2:1:-1}"
Exec Style
Exec-style commands are passed through an array. The syntax is stricter, and the command is expected to be in the order of command
, flags
, and arguments
. Exec commands run in the same main process. A new layer is added to the image for each exec command.
ENTRYPOINT ["echo", "Hello", "World"]
Sensible Defaults
RUN
: Use shell style because it improves readability and provides a command shell by default.CMD
andENTRYPOINT
: Use exec style so that your executables run in the main process. Also, exec style is the only way to passCMD some_arg
anddocker run some_arg
arguments to the executable.
CMD and ENTRYPOINT
ENTRYPOINT
The entry point is the executable of a docker container. Container developers use the entry point to set the default behaviour. The entry point is much harder to override using the docker run command. Here are some example entries:
# official nodejs image
ENTRYPOINT ["docker-entrypoint.sh"]
# custom python image
ENTRYPOINT ["python3"]
# npm based image
ENTRYPOINT ["npm"]
CMD
The docker documentation specifies that:
“The CMD instruction sets the command to be executed when running a container from an image.”
When used in conjunction with ENTRYPOINT
, the CMD
instructions set arguments to run for an executable.
If npm
was set as the executable, some example commands might be start
, test
, and format
. Here is another example using Python. I set the executable to be ENTRYPOINT [ "python" ]
this allows for the following docker-compose setup:
test:
build:
context: .
command: ["-m", "pytest"]
black:
build:
context: .
command: ["-m", "black", "--check", "."]
flake8:
build:
context: .
command: ["-m", "flake8", "."]
Sensible Defaults
When selecting an executable for your project, consider combinations that support different utilities and applications such as formatting, testing, and running applications. If you can, be specific and narrow down your choices, for example, using ENTRYPOINT ["npm"]
. If you want to maximize compatibility, you can set your entry point as an interactive base or shell prompt, for example, ENTRYPOINT ["/bin/bash"]
.