Docker CMD vs ENTRYPOINT: explaining the difference

Introduction

We IT people LOVE tinkering with new tech stuff, and Docker is no exception. As a matter of fact, Docker was ranked as the #1 most wanted platform, #2 most loved platform, and #3 most broadly used platform in the 2019 Stack Overflow Developer Survey, and #1 most wanted platform, #2 most loved platform and #3 most popular platform in the 2020 edition of the same survey.

If you've bumped into this article, chances are that you have been bamboozled by the fruit doggo difference between the CMD and ENTRYPOINT instructions defined in a Dockerfile, used to describe how a Docker container should be run.

But what's a Docker container?

Containers are lightweight, standalone, executable packages of software designed for running specific tasks, no matter if short-lived or long-running. Therefore, a container's lifecycle depends on the ongoing process inside of it.

Once the process stops, the container stops as well.

Ok, but what role is our Dockerfile playing here?

Containers are dependent on images and use them to construct a run-time environment in order to run an application. A Dockerfile is a script which role is to define the process which leads to the creation of a final image, and how to run a container bound to said image.

The process of creating a Docker image usually begins with a FROM command, defining a base image to build our image upon. We usually follow up with a bunch of RUN instructions, used to run commands which modify the underlying filesystem.

Each RUN instruction creates a new image layer that contains a modification to the filesystem.

Fine. Now what about the CMD vs ENTRYPOINT stuff?

CMD and ENTRYPOINT are two different types of instructions used to define how a Docker container should be run. Let's dive into the details of each one:

CMD

A CMD instruction defines the default command used to run a Docker container from an image.

Given a simple image like the following:

FROM alpine
CMD ["echo", "Hello, World!"]

Running it with:

docker container run my-container

Will yield the following result:

Hello, World!

A Dockerfile can contain multiple CMD instructions, but every single one of them, except for the last one, will be ignored.

A CMD instruction can be overridden by the arguments passed to docker container run, like:

docker container run my-container echo "Hello again!"

Will yield:

Hello again!

ENTRYPOINT

ENTRYPOINT instructions define, just like their CMD siblings, the default command used to start a container.

FROM alpine
ENTRYPOINT ["echo", "Hello, World!"]

Will yield:

Hello, World!

Cool, so... what's the difference at this point?

Well, the main difference is that, if both a CMD and ENTRYPOINT instructions are defined inside a Dockerfile, the CMD instruction will be concatenated to the ENTRYPOINT one:

FROM alpine
ENTRYPOINT ["echo"]
CMD ["Hello, World!"]

Wil lead to us seeing:

Hello, World!

Also, while CMD instructions are, by design, made do be easily overridden by passing arguments to docker container run commands, ENTRYPOINT have purposely been made harder to override manually, by forcing user to use a --entrypoint flag.

Conclusions

This design leads us to a consistent pattern. And we like patterns, patterns are good for our mental health:

We can use ENTRYPOINT to define a base command which always gets executed, and CMD to define default arguments for this command, easily overridable by passing custom args to docker container run.

Publication date: 26/06/2021