The difference between CMD and ENTRYPOINT is something that I had always wondered about. On the surface, these seem to indicate that they are two different ways to achieve the same thing. But looking at them a little deeper it’s clear to see that they actually two separate, but equally important, concepts in a Dockerfile.
According to the Docker documentation –
The main purpose of a CMD is to provide defaults for an executing container
An ENTRYPOINT allows you to configure a container that will run as an executable
So what is the difference between CMD and ENTRYPOINT
ENTRYPOINT’s define the executable the container will run and CMD defines default parameters that will be overridden by arguments given to docker run.
By defining an ENTRYPOINT in your Dockerfile you are specifying the intended use of the container whereas with a CMD instruction you are effectively letting users override this with command-line arguments.
How do CMD and ENTRYPOINT work together
CMD can be used to define the default parameters for ENTRYPOINT. Using this method, you are allowing users to supply different command-line arguments for ENTRYPOINT but are still specifying what executable is to be run in the container.
You can think of CMD and ENTRYPOINT working together by concatenating all of the words together to form a shell command with arguments. For example:
FROM ubuntu CMD [“parameter1”,”parameter2”] ENTRYPOINT [“executable”,”parameter3”, “parameter4”]
Would result in the following command being executed:
Executable parameter3 parameter4 parameter1 parameter2
There are four rules that you should be aware of when working with CMD’s and ENTRYPOINT’s together. These are directly from the docker documentation:
- Dockerfile should specify at least one of CMD or ENTRYPOINT commands.
- ENTRYPOINT should be defined when using the container as an executable.
- CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a container.
- CMD will be overridden when running the container with alternative arguments.
Rule 1 will result in an error if neither a CMD nor ENTRYPOINT instruction is included in the Dockerfile.
Rule 2 relates to containers that are treated as executables. In my experience, executable images are images whose intent is to either run locally for some short-lived process, like displaying content and then quitting (like “Hello World”), or performing one task like updating a database.
Images that are not considered executable are what I believe run long-running processes like web servers or databases. So the difference to me is in the length of the process run combined with the intent of the reason to run the image.
Rules 3 and 4 are closely linked in that they both relate to arguments, it is just another way of saying that CMD parameters aren’t set in stone and it is expected that users of the image will often supply alternative arguments to the ones specified in the CMD.
So what are shell and exec forms?
The shell and exec forms relate to the syntax of the the statements. For example, the shell form of ENTRYPOINT looks like:
ENTRYPOINT command paramater1 parameter2
whereas the exec form looks like
ENTRYPOINT [“executable”,”parameter1”,”parameter2 ”]
When using the exec format you need to enclose words in double-quotes and not single-quotes.
A common trap in using CMD with exec form is expecting access to the shell. For example, variable substitution won’t occur when calling the following CMD:
In this instance, you should supply the shell executable and the appropriate parameters like so:
CMD [“/bin/sh”,”-c”,”echo $PATH”]
In the above example, I’m using the single-character option of ‘c’ to exit the shell when the command is complete.
You could also just use the shell form to invoke a shell as follows:
FROM ubuntu CMD echo “bernieslearnings.com is the place to be"
This will execute in
The preferred form is the exec form for ENTRYPOINT’s. An ENTRYPOINT may be overridden by specifying the —entrypoint flag in a docker run statement. Running ENTRYPOINT using the shell form causes your ENTRYPOINT to be started as a subcommand of
This has some serious side effects in that your executable won’t be the containers PID 1 and will not receive Unix signals such as SIGTERM when stopping your container.
It’s for this reason that I prefer to have an ENTRYPOINT in exec form for each of my Dockerfiles, tracking down why containers won’t stop or other side effects can be very time consuming just from making a poor choice in form when building your containers.
Similarly to ENTRYPOINT, Dockerfile’s can only have one CMD instruction. If you have more than one in a Dockerfile, only the last CMD will be used.
When using CMD in the shell form then the command will execute in
/bin/sh -c. If you want to run CMD outside of a shell you need to use the exec form and give the full path to the command as the first string in the array with the parameters as the remaining strings in the array.
Some example CMD and ENTRPOINT Dockerfile’s
Example 1 – No ENTRYPOINT
Starting with a simple Dockerfile, we can demonstrate a Dockerfile with no ENTRYPOINT and a CMD:
FROM alpine:latest RUN apk add sl CMD ["sl"]
Then we can build this image from the Dockerfile:
docker build --tag sl .
And then run the newly created image in interactive mode:
docker run -it sl:latest
Example 2 – No CMD
This Dockerfile will just make use of the ENTRYPOINT instruction in exec form:
FROM alpine:latest RUN apk add sl ENTRYPOINT ["sl"]
Now we can build and run again:
docker build --tag sl . docker run -it sl:latest
Example 3 – ENTRYPOINT and CMD
This example will use both CMD and ENTRYPOINT. It’s important to remember that in order to use both CMD and ENTRYPOINT you need to use the exec form for both instructions.
FROM alpine:latest RUN apk add sl ENTRYPOINT ["sl"] CMD ["-a"]
And again, we’ll build and run the image in interactive mode:
docker build --tag sl . docker run -it sl:latest
As you can see, the ENTRYPOINT will launch “sl” with the parameter “-a” from the CMD instruction.
These are basic examples that just highlight the use of CMD and ENTRYPOINT.
Other Docker articles on bernieslearnings:
Here are some links for further reading
- Docker docs CMD: https://docs.docker.com/engine/reference/builder/#cmd
- Docker docs ENTRYPOINT: https://docs.docker.com/engine/reference/builder/#entrypoint
- Docker docs Understand how CMD and ENTRYPOINT interact: https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact
- Docker docs Build: https://docs.docker.com/engine/reference/commandline/build/