Docker CMD evaluation with ENTRYPOINT

1.1k views Asked by At

I have a Dockerfile that falls into the exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd category in the matrix found in Understand how CMD and ENTRYPOINT interact. The behavior is not what I'm expecting. I was expecting /bin/sh -c exec_cmd p1_cmd to evaluate first then get passed into exec_entry p1_entry. What I am observing is that /bin/sh -c exec_cmd p1_cmd literally gets passed into exec_entry p1_entry which I think is funny.

To provide more context, I am specifically deriving a new Dockerfile from an existing Dockerfile where the parent has:

ENTRYPOINT ["/bin/registrator"]

I want to pass in specific command-line parameters from my Dockerfile:

FROM gliderlabs/registrator:v7
CMD echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"

When I run my Docker image in a container:

$ docker run --rm --name=test-registrator --volume=/var/run/docker.sock:/tmp/docker.sock -e "EXTERNAL_IP=<some-ip>" -e "CONSUL_HOST=<some-consul-hostname>:8500" my/registrator

I get the following error:

2016/12/28 19:20:46 Starting registrator v7 ...
Extra unparsed arguments:
  -c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"
Options should come before the registry URI argument.

Usage of /bin/registrator:
  /bin/registrator [options] <registry URI>

-cleanup=false: Remove dangling services
-deregister="always": Deregister exited services "always" or "on-success"
-internal=false: Use internal ports instead of published ones
-ip="": IP for ports mapped to the host
-resync=0: Frequency with which services are resynchronized
-retry-attempts=0: Max retry attempts to establish a connection with the backend. Use -1 for infinite retries
-retry-interval=2000: Interval (in millisecond) between retry-attempts.
-tags="": Append tags for all registered services
-ttl=0: TTL for services (default is no expiry)
-ttl-refresh=0: Frequency with which service TTLs are refreshed

This means that -c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST" is literally getting passed into /bin/registrator as the parameter.

Am I doing something wrong or is this a limitation of the use case where /bin/sh -c exec_cmd p1_cmd does not get evaulated first before getting passed into the ENTRYPOINT? If the latter is true, then can you also explain the usefulness of this use case?

2

There are 2 answers

4
Vlad On

Yes. This is exactly how it is supposed to work.

The value of CMD is just passed as a parameter to the ENTRYPOINT.

Main difference between CMD and ENTRYPOINT is that CMD just provides default command argument to the ENTRYPOINT program and it's usually overridden by the arguments to run command. On the other hand you have to redefine ENTRYPOINT explicitly with --entrypoint option if you want different command to be executed.

Also, notice there is a difference how things are executed depending on the way ENTRYPOINT and CMD are defined in the Dockerfile. When they are defined as an array in the form of ['arg1', 'arg2'] this array is passed as is to the ENTRYPOINT command, with the first element of ENTRYPOINT being the program being executed. In the other case when they are defined as a simple string like arg1 arg2 this string is first passed is prepended by "/bin/sh -c" note that Docker does not execute /bin/sh and returns the result of evaluation back, that string itself is passed to the ENTRYPOINT program.

So in your case you have to use array method of passing the arguments:

CMD  [-ip, $EXTERNAL_IP,  consul://$CONSUL_HOST]
0
Khaled Boussoffara On

Are you struggling to understand the difference between CMD and ENTRYPOINT in Dockerfile? Check out this article, 'Understanding the Difference Between CMD and ENTRYPOINT in Dockerfile:A Comprehensive Guide,' at https://code-craft.fr/understanding-the-difference-between-cmd-and-entrypoint-in-dockerfile-a-comprehensive-guide/. It provides a comprehensive guide on the differences and best practices for effective use. This may help you gain a better understanding of these crucial components in Dockerfile.