Which instruction in Dockerfile is used to execute a command with container?

In a Dockerfile, we often encounter instructions like run, cmd, or entrypoint. At first glance, they are all used for specifying and running commands. But what's the difference between them? And how do they interact with one another?

In this tutorial, we'll answer these questions. We'll present what each of these instructions does and how they work. We'll also look at what role they play in building an image and running a Docker container.

2. Setup

To start, let's create a script, log-event.sh. It simply adds one line to a file and then prints it:

#!/bin/sh

echo `date` [email protected] >> log.txt;
cat log.txt;

And now, let's create a simple Dockerfile:

FROM alpine
ADD log-event.sh /

It'll make use of our script by appending lines to log.txt in different scenarios.

3. The run Command

The run instruction executes when we build the image. That means the command passed to run executes on top of the current image in a new layer. Then the result is committed to the image. Let's see how this looks in action.

Firstly, we'll add a run instruction to our Dockerfile:

FROM alpine
ADD log-event.sh /
RUN ["/log-event.sh", "image created"]

Secondly, let's build our image with:

docker build -t myimage .

Now we expect to have a Docker image containing a log.txt file with one image created line inside. Let's check this by running a container based on the image:

docker run myimage cat log.txt

When listing the contents of the file, we'll see an output like this:

Fri Sep 18 20:31:12 UTC 2020 image created

If we run the container several times, we'll see that the date in our log file doesn't change. This makes sense because the run step executes at image build time, not at the container runtime.

Let's now build our image again. We notice the creation time in our log didn't change. This happens because Docker caches the result for the run instruction if the Dockerfile didn't change. If we want to invalidate the cache, we need to pass the –no-cache option to the build command.

4. The cmd Command

With the cmd instruction, we can specify a default command that executes when the container is starting. Let's add a cmd entry to our Dockerfile and see how it works:

...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]

After building the image, let's now run it and check the output:

$ docker run myimage
Fri Sep 18 18:27:49 UTC 2020 image created
Fri Sep 18 18:34:06 UTC 2020 container started

If we run this multiple times, we'll see that the image created entry stays the same. But the container started entry updates with every run. This shows how cmd indeed executes every time the container starts.

Notice we've used a slightly different docker run command to start our container this time. Let's see what happens if we run the same command as before:

$ docker run myimage cat log.txt
Fri Sep 18 18:27:49 UTC 2020 image created

This time the cmd specified in the Dockerfile is ignored. That's because we have specified arguments to the docker run command.

Let's move on now and see what happens if we have more than one cmd entry in the Dockerfile. Let's add a new entry that will display another message:

...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
CMD ["/log-event.sh", "container running"]

After building the image and running the container again, we'll find the following output:

FROM alpine
ADD log-event.sh /
0

As we can see, the container started entry is not present, only the container running is. That's because only the last cmd is invoked if more than one is specified.

5. The entrypoint Command

As we saw above, cmd is ignored if passing any arguments when starting the container. What if we want more flexibility? Let's say we want to customize the appended text and pass it as an argument to the docker run command. For this purpose, let's use entrypoint. We'll specify the default command to run when the container starts. Moreover, we're now able to provide extra arguments.

Let's replace the cmd entry in our Dockerfile with entrypoint:

FROM alpine
ADD log-event.sh /
1

Now let's run the container by providing a custom text entry:

FROM alpine
ADD log-event.sh /
2

We can see how entrypoint behaves similarly to cmd. And in addition, it allows us to customize the command executed at startup.

Like with cmd, in case of multiple entrypoint entries, only the last one is considered.

6. Interactions Between cmd and entrypoint

We have used both cmd and entrypoint to define the command executed when running the container. Let's now move on and see how to use cmd and entrypoint in combination.

One such use-case is to define default arguments for entrypoint. Let's add a cmd entry after entrypoint in our Dockerfile:

FROM alpine
ADD log-event.sh /
3

Now, let's run our container without providing any arguments, and with the defaults specified in cmd:

FROM alpine
ADD log-event.sh /
4

We can also override them if we choose so:

FROM alpine
ADD log-event.sh /
5

Something to note is the different behavior of entrypoint when used in its shell form. Let's update the entrypoint in our Dockerfile:

FROM alpine
ADD log-event.sh /
6

In this situation, when running the container, we'll see how Docker ignores any arguments passed to either docker run or cmd.

7. Conclusion

In this article, we've seen the differences and similarities between the Docker instructions: run, cmd, and entrypoint. We've observed at what point they get invoked. Also, we've taken a look at their uses and how they work together.

Which command executes a Docker container?

The docker exec command runs a new command in a running container. The command started using docker exec only runs while the container's primary process ( PID 1 ) is running, and it is not restarted if the container is restarted. COMMAND will run in the default directory of the container.

What Dockerfile instruction is used to execute a command in a new layer?

The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile .

What is the command to run the container?

To run a command in a certain directory of your container, use the --workdir flag to specify the directory: docker exec --workdir /tmp container-name pwd.

What is the command to run Dockerfile?

RUN is the central executing directive for Dockerfiles. USER sets the UID (or username) which is to run the container. VOLUME is used to enable access from the container to a directory on the host machine. WORKDIR sets the path where the command, defined with CMD, is to be executed.