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.
Suppose you want to build and run a docker image that pings www.google.com.
We can accomplish that by starting to write the following Dockerfile:
# Base ImageFROM ubuntu:20.04# Required installationsRUN 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 ImageFROM ubuntu:20.04# Required installationsRUN apt-get update && apt-get -y install iputils-pingCMD ["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.
We repeat the process, only this time we replace CMD with ENTRYPOINT in our Dockerfile:
# Base ImageFROM ubuntu:20.04# Required installationsRUN apt-get update && apt-get -y install iputils-pingENTRYPOINT ["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.
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 aping
command as well. We could potentially provide such adocker run
command:
docker run -d pinger python3 sample.py
And this would executepython3 sample.py
if we have python3 installed in our container, and sample.py file in the directory.
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.
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 ImageFROM ubuntu:20.04# Required installationsRUN apt-get update && apt-get -y install iputils-pingENTRYPOINT ["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