I am looking at Docker’s documentation to understand what would be behavior of ENTRYPOINT
defined in exec form and CMD
defined in shell form.
The example in the docs only shows something like exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
which does not tell me anything.
For example, what if we had:
ENV JAVA_OPTS '-XX:+UseG1GC -Xms512m -Xmx1536m'
ENTRYPOINT ["java"]
CMD $JAVA_OPTS -jar app.jar
Would the problem with signal propagation exist here (in other words, would any extra subshell be spawned here)?
2
Answers
It took me a while but I finally figured out what is the point of
/bin/sh -c
in this use-case. We can for example use tini as an entrypointENTRYPOINT ["tini", "--"]
and then a shell for of CMD, but we need to use
exec
in order to replace a subshell, that isCMD exec java $JAVA_OPTS -jar app.jar
ENTRYPOINT
orCMD
are not JSON arrays, they are interpreted as strings and converted to a length-3 array["/bin/sh", "-c", "..."]
.So in your example, the final command list would be
or in Bourne shell syntax
This passes the shell interpreter
/bin/sh
as an argument tojava
; that almost certainly is not what you intend.If the
CMD
is anything other than a complete command, it must use the JSON-array syntax, which in turn means it can’t use any shell features and it can’t expand environment variable references. This would include both the "container-as-command" pattern whereENTRYPOINT
is the command to run andCMD
its arguments, and the antipattern you show here whereENTRYPOINT
is the interpreter only (and you have to repeat the-jar app.jar
option in adocker run
command override).I prefer a setup where
CMD
is always a complete shell command. If you have anENTRYPOINT
at all, it’s a script that does some startup-time setup and then runsexec "$@"
to run the command passed as arguments. This can accept either form ofCMD
.