In this blog, we will discuss a topic that constantly confuses the beginners. We will discuss the usage of the CMD and ENTRYPOINT instructions in Dockerfile. We will also get to know how we can use CMD and ENTRYPOINT instructions effectively.
Let’s start with a simple scenario!
Let’s suppose we were to run a docker container from an ubuntu image.
When we run a docker run ubuntu command, it will run an instance of an ubuntu image and will exit immediately.
Now, if we run docker ps to list the running containers, it shows an empty list.
If we run a docker ps -a to list all the stopped containers, now it shows us that our newly created container has exited and is in a stopped state.
Why Container Exited?
The container exited because unlike virtual machines containers are not meant to host an operating system! They are meant to run a specific task or a process. e.g. An instance to host a web server, an application server, a database or simply to carry out any type of computation. A container exists as long as some task or process is running or alive in it. So, as soon as a process inside a container stops or crashes, the container also stops and exits.
The CMD Instruction
As we have discussed above that “as soon as a process inside a container stops or crashes, the container stops”. So who defines what process will run within a container? Let’s look at the Dockerfile of a popular docker image nginx .
If we look clearly at the above Dockerfile we can see an instruction called CMD. CMD stands for “Command”. This instruction defines the process that will run when a container will start.
Now let’s have a look at our “ubuntu” container Dockerfile that exited a few seconds ago.
On startup, CMD will run bash as a default command, but bash is not a continuous process like a web server or database server, it is simply a shell that listens for inputs from the terminal when it doesn’t find any terminal, it exits.
When we ran an ubuntu container earlier using “docker run ubuntu”, docker created a container from the ubuntu image and launched a bash program. By default, the docker doesn’t attach a terminal with the container when it is run and so the bash program was unable to find the terminal, so it stopped and exited.
So how do we specify a different command to start a container?
The special feature of CMD is that we can override it by appending a command to docker run.
A look at the command reference shows that the actual syntax is docker container run [OPTIONS] IMAGE [COMMAND] [ARG…], meaning it takes an optional command argument after the image name.
So If we run “docker run ubuntu sleep 5“, the container will start and waits for 5 seconds and then only it will exit. Here we have overridden the default command specified within the image with our appended “sleep 5” command.
Let’s take another example!
FROM alpine:latest
CMD ["echo", "Hello from CMD"]
This Dockerfile uses Alpine Linux as a base image and executes the echo command.
After creating an image using docker build -t my-image .
, running a container will yield the following output:
$ docker run my-image
Hello from CMD
Now let’s override the CMD by appending the run command!
$ docker run my-image echo "Hello from the CLI" Hello from the CLI
So we have successfully overridden the default CMD command.
The ENTRYPOINT Instruction
Just like CMD, ENTRYPOINT instruction also defines a starting command for containers. However, we don’t usually override it. Entrypoint instruction is a good option for the containers that always run the same service and act as an executable.
What matters the most, though, is that CMD
is always appended to ENTRYPOINT
.
We can easily verify this using the following Dockerfile that contains both instructions:
FROM alpine:latest
ENTRYPOINT ["echo"]
CMD ["Hello from CMD"]
Re-building the image using “docker build -t my-image .” and running the container will yield the same output, despite the fact that echo and its arguments have been split apart.
$ docker run my-image
Hello from CMD
For your Information, CMD is still overridable! Since CMD
contains the arguments for “echo"
, we can override these arguments from the command line. They will get appended to “ENTRYPOINT
” just as before.
$ docker run my-image "Hello from the CLI"
Hello from the CLI
NOTE!
This pattern is widely used: ENTRYPOINT defines a fixed command that is always executed, and CMD
defines default arguments for this command, and CMD commands can be overridden by docker run command
.
Overriding ENTRYPOINT
In the previous section, we discussed that the ENTRYPOINT instruction is usually not overridden by the docker run command because, in the Dockerfile, the ENTRYPOINT command defines the executable, while CMD sets the default parameter.
We can override an entry point nonetheless, we may want to override the default executable and run a shell inside a container. In that case, we need to use the --entrypoint
flag and run the container using the following syntax:
docker run --entrypoint [new_command] [docker_image] [optional:value]
To override the default echo message in our example and run the container interactively, we use the command “docker run –entrypoint /bin/bash my-image” and the output shows that we are now inside the container.
$ docker run --entrypoint /bin/bash my-image
root@45874b65748:/#
We should keep in mind that this is only temporary. Once we exit out of the container and run it again using the standard docker run
command, it executes the default ENTRYPOINT instruction.
When to use CMD and when to use ENTRYPOINT?
One should always choose CMD if you need to provide a default command and/or arguments that can be overwritten from the command line when the docker container runs.
It is advisable to use ENTRYPOINT rather than CMD when building executable Docker images.
Tip💡
It is a good practice to use both ENTRYPOINT and CMD instructions together in Dockerfile.
In such cases, the executable is defined with ENTRYPOINT, while CMD specifies the default parameter. However, in that case, we can’t override the command itself. Only the parameters for the CMD instruction can be overridden while executing Docker run statement.
Conclusion
In this blog, we discussed the CMD and the ENTRYPOINT instructions. We also discussed when to use these instructions. Cheers!
References
