Dockerfile: CMD and ENTRYPOINT: shell and exec forms
• 290 words • 2 min • updated
Today I filed a github issue against the
dockerfmt project, which I copy
verbatim here given its surprising behavior.
reteps/dockerfmt#33 #
Consider this sample Dockerfile (abridged version of a real-world scenario):
ENTRYPOINT sleep infinity
CMD sleep infinityLet’s run dockerfmt (v0.3.7) in it:
% dockerfmt Dockerfile
ENTRYPOINT ["sleep", "infinity"]
CMD ["sleep", "infinity"]At first glance, everything looks OK. The problem is that this transformation is not a no-op.
Looking at the docs:
- https://docs.docker.com/reference/dockerfile/#cmd
- https://docs.docker.com/reference/dockerfile/#shell-and-exec-form
If CMD is used to provide default arguments for the ENTRYPOINT instruction, both the CMD and ENTRYPOINT instructions should be specified in the exec form.
The difference is:
- the original code yields
sleep infinity(correct!) - the transformed code yields
sleep infinity sleep infinity, which is an error (sleep:no such argument sleep)
One could argue that the original code is odd – the following would be conceptually simpler, and more idiomatic:
ENTRYPOINT ["sleep"]
CMD ["infinity"]Or even:
ENTRYPOINT ["sleep", "infinity"]Nonetheless, IMHO dockerfmt should not change the behavior in this case.
Notes #
shell and exec
forms have
distinct forms:
INSTRUCTION ["executable", "param1", "param2"](exec form)INSTRUCTION command param1 param2(shell form)
The exec form makes it possible to avoid shell string munging, and to invoke commands using a specific command shell, or any other executable. It uses a JSON array syntax, where each element in the array is a command, flag, or argument.
The shell form is more relaxed, and emphasizes ease of use, flexibility, and readability. The shell form automatically uses a command shell, whereas the exec form does not.
dockerfmt
prefers
the exec form, for whatever reason.
There’s even a code comment:
// this can technically change behavior. https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact
Surprise surprise! The issue I reported is precisely due to a change of behavior.