How are CMD and ENTRYPOINT different in a Dockerfile?

Overview

The main difference between CMD and ENTRYPOINT in Docker is that execution-wise, the default arguments provided by CMD can get overridden, whereas those provided by ENTRYPOINT cannot. Let's illustrate this with the help of an example.

Example

Suppose you want to build and run a docker image that pings www.google.com.

Defining default arguments

Using CMD

We can accomplish that by starting to write the following Dockerfile:

# Base Image
FROM ubuntu:20.04
# Required installations
RUN apt-get update && apt-get -y install iputils-ping

In our Dockerfile:

  • Line 2: We use ubuntu as our base image.

  • Line 5: We do the necessary installations required to run the ping command.

Next, we can then use CMD to add a command that pings www.google.com:

# Base Image
FROM ubuntu:20.04
# Required installations
RUN apt-get update && apt-get -y install iputils-ping
CMD ["ping", "www.google.com"]

Now we build our image using the Dockerfile and run it using the following commands (pinger is the name of the image we're building):

docker build -t pinger .

docker run -d pinger

And we successfully manage to run a container that continuously pings www.google.com.

Note: -d flag in our run command allows us to run container in the background and frees out terminal for further usage.

Using ENTRYPOINT

We repeat the process, only this time we replace CMD with ENTRYPOINT in our Dockerfile:

# Base Image
FROM ubuntu:20.04
# Required installations
RUN apt-get update && apt-get -y install iputils-ping
ENTRYPOINT ["ping", "www.google.com"]

We again build and run the Dockerfile using the same commands as before, and we notice that thus far, there has been no difference between the two executions.

Providing additional arguments through the terminal

Using CMD

Before we delve into where the difference between the two lies, it is worth paying some notice to the docker run command. The syntax is as follows: docker run <optional flags> <image name> <command> . -d is the optional flag that we are using, pinger is our image name, and whatever we may include after our image name will become part of our command that is fed to either CMD/ENTRYPOINT.

We now build and run both our Dockerfiles from before, only this time we feed additional arguments to the docker run command.

First, we build our Dockerfile containing the CMD command and run it using the following command:

docker run -d pinger ping www.youtube.com

We can see that our program is now pinging www.youtube.com instead of www.google.com. The extra arguments that we provide to the docker run command replace the existing arguments defined in the Dockerfile, and this is what is executed:

ping www.youtube.com

Note: The entire command provided to CMD is overwritten. In the above example, "ping" remains constant, but this is because our command provided in the additional argument is a ping command as well. We could potentially provide such a docker run command:

docker run -d pinger python3 sample.py

And this would execute python3 sample.py if we have python3 installed in our container, and sample.py file in the directory.

Using ENTRYPOINT

Next, we run the Dockerfile containing the ENTRYPOINT command and run it using the following command:

docker run -d pinger ping www.youtube.com

In this case, however, the program pings www.google.com and then immediately dies. The additional arguments to the docker run command are appended to the existing arguments defined in the Dockerfile, so this is what we try to run:

ping www.google.com ping www.youtube.com

Because this command contains a syntax error, the full command fails to get executed and our program exits. To remedy this, we can alter our docker run command to add && at the start of our additional arguments:

docker run -d pinger && ping www.youtube.com

So we execute the following command:

ping www.google.com && ping www.youtube.com

And we can see our program now pings both www.google.com and www.youtube.com.

Combining ENTRYPOINT and CMD

We can combine CMD and ENTRYPOINT if we want to fix some parameters of the commands we want to run and let others remain variable. In the example above, we may want to ensure that the container always pings a website, but the website to be pinged remains a variable.

We could do that by combining ENTRYPOINT and CMD in the Dockerfile:

# Base Image
FROM ubuntu:20.04
# Required installations
RUN apt-get update && apt-get -y install iputils-ping
ENTRYPOINT ["ping"]
CMD ["www.google.come"]

Now we first build our image, and run it without providing any extra arguments:

docker build -t pinger

docker run -d pinger

And our container runs the following command:

ping www.google.com

If we alter the docker run command to run the following:

docker run -d pinger www.youtube.com

Our container now runs the following command instead:

ping www.youtube.com

We can see that ping has remained constant while www.google.com has been replaced by www.youtube.com. We can combine both ENTRYPOINT and CMD in this manner to utilize the individual properties provided by both commands.

Free Resources

Copyright ©2024 Educative, Inc. All rights reserved