Skip to content

Instantly share code, notes, and snippets.

@joonaspessi
Last active October 15, 2020 13:51
Show Gist options
  • Save joonaspessi/cacd118f56fc8c62d788c11e65e1fa41 to your computer and use it in GitHub Desktop.
Save joonaspessi/cacd118f56fc8c62d788c11e65e1fa41 to your computer and use it in GitHub Desktop.
Docker ENTRYPOINT vs CMD

Docker ENTRYPOINT vs CMD

ENTRYPOINT defines the main executable that Docker will use. If entrypoint is not given, then CMD will be used as a command that is executed.

CMD defines the default arguments for the ENTRYPOINT. Note that CMD argument can be overridden when running the container with alternative arguments.

We can think them as pair that are concatenated ENTRYPOINT + CMD.

For example, let's build container that pings three times a given network host. If no host is given, then it should ping localhost as a default.

FROM alpine:latest
ENTRYPOINT ["/bin/ping", "-c", "3"]
CMD ["localhost"]

(As a base image, we use alpine:latest which is a minimalistic Linux image)

So first we replace Docker's default entrypoint /bin/sh -c, as we want to use /bin/ping.

Then we will set default parameter for our entrypoint to be localhost CMD ["localhost"].

Now we can build our Dockerfile to an image using tag pinger:latest:

docker build -t pinger:latest .

Then we can run our container by taking advantage of the default CMD argument. As we can see, our pinger is using the localhost as specified in CMD

❯ docker run pinger:latest
PING localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.042 ms
64 bytes from 127.0.0.1: seq=1 ttl=64 time=0.093 ms
64 bytes from 127.0.0.1: seq=2 ttl=64 time=0.154 ms

--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.042/0.096/0.154 ms

To test overriding the default CMD argument, we can give argument for docker run. For example we can ping google.fi with following command:

❯ docker run pinger:latest google.fi
PING google.fi (172.217.21.131): 56 data bytes
64 bytes from 172.217.21.131: seq=0 ttl=37 time=70.218 ms
64 bytes from 172.217.21.131: seq=1 ttl=37 time=69.093 ms
64 bytes from 172.217.21.131: seq=2 ttl=37 time=73.889 ms

--- google.fi ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 69.093/71.066/73.889 ms

Seems to be working as expected.

EXEC vs SHELL forms

Now comes the interesting part. Both CMD and ENTRYPOINT supports EXEC and SHELL modes and there's a serious caveat to mess things up with them.

In EXEC mode, command itself is executed. In Dockerfiles, EXEC mode uses []-parenthesis syntax. For example ENTRYPOINT ["/bin/ping","-c","3"].

In SHELL mode, command is wrapped with /bin/bash -c. It's useful when you need to evaluate for example environment variables. Docker SHELL mode is used when not wrapping the command with []-parenthesis. For example ENTRYPOINT /bin/ping -c 3.

So it's not the same thing to write ENTRYPOINT and CMD values with or without []-parenthesis.

Let see an example for the Dockerfile and their corresponding output commands:

ENTRYPOINT /bin/ping -c 3
CMD localhost
=> /bin/sh -c '/bin/ping -c 3' /bin/sh -c localhost

ENTRYPOINT ["/bin/ping","-c","3"]
CMD localhost
=> /bin/ping -c 3 /bin/sh -c localhost

ENTRYPOINT /bin/ping -c 3
CMD ["localhost"]
=> /bin/sh -c '/bin/ping -c 3' localhost

ENTRYPOINT ["/bin/ping","-c","3"]
CMD ["localhost"]
=> /bin/ping -c 3 localhost

For our case, only the last example will work. It will actually produce the output that combines the command correctly with the arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment