Using the Dockerfile ENTRYPOINT and CMD Instructions

Published:14 July 2021 - 5 min. read

Azure Cloud Labs: these FREE, on‑demand Azure Cloud Labs will get you into a real‑world environment and account, walking you through step‑by‑step how to best protect, secure, and recover Azure data.

If you’ve ever needed to run a command or two in your Docker container on startup, this tutorial is for you. Using the Dockerfile ENTRYPOINT and CMD instructions, you can run as many startup commands as you’d like.

In this tutorial, you’ll learn how to use the ENTRYPOINT and CMD instructions to run startup commands in a Dockerfile and understand the differences between them.

Prerequisites

Since this tutorial will be a hands-on demonstration, be sure you have the following in place:

  • A Windows 10 PC – Windows 10 v10.0.19042 was used in this tutorial.
  • Docker Desktop – This tutorial uses Docker Desktop v3.3.1.

Creating a Dockerfile

Before you can run Docker container startup commands, you must first create a Dockerfile. A Dockerfile is a text document that contains a list of commands to build containers, Docker images and determines how a Docker image is created.

1. First, open PowerShell as administrator.

2. Create a new folder to store the Dockerfile and all associated files this tutorial will use and change to that directory. This tutorial is using ~/docker.

mkdir ~/docker
cd docker

3. Now, create a blank text file named Dockerfile with the following command.

cd > Dockerfile

Alternatively, you can create a Dockerfile with the following command if you’re on Linux or Mac OS.

touch Dockerfile

4. Finally, add the following content into the Dockerfile

FROM ubuntu:20.04

You now have created a soon-to-be Dockerfile!

Building a Docker Image

Now that you’ve created your Dockerfile, you must build a Docker image to execute the commands written in your Dockerfile ENTRYPOINT and CMD instructions. One way to build an image is by using the build command.

While in the ~/docker directory, run the following command. The command below creates a Docker image called demo (-t demo) from the Dockerfile in ~/docker by specifying the current working directory (.).

docker build -t demo .
Building a Docker Image
Building a Docker Image

Running a Docker Container

After you’ve built the Docker image, you’ll need a container to run the Docker image that will execute the commands from the Dockerfile ENTRYPOINT and CMD instructions.

To run a Docker container, invoke the run command to create a writeable container layer over the Docker image (demo). The below example is using the -it parameter to interactively connect to the container so you can see the sample output.

docker run -it demo
Running a Docker Container
Running a Docker Container

Exec vs. Shell Form

When you begin to work with a Dockerfile and figure out how to run startup commands, you may come across two different methods of defining these commands. Each method will invoke commands but does so a bit differently.

When Docker executes commands, it can do so directly called exec or go through the container’s shell (/bin/sh -c on Linux or cmd /S /C on Windows) called shell.

You’ll notice commands executed via exec have an instruction followed by the executables to invoke followed by one or more command-line arguments, as shown below.

ENTRYPOINT ["executables", "parameter1", "parameter2", ...]
CMD ["executables", "parameter1", "parameter2:, ...]

Writing commands in shell form, on the other hand, doesn’t require wrapping commands in square brackets, as shown below.

ENTRYPOINT <command> "parameter1"
CMD <command> "parameter1"

If you don’t specify a argument to CMD, Docker will always execute the command in exec form e.g. CMD <command>.

If you’re just starting out, differentiating between these two command invocations won’t matter too much but as you get more advanced, you’ll soon see benefits and drawbacks to each.

Running Startup Commands

Let’s now get in the meat of this tutorial and get your hands dirty by walking through a few examples of running startup commands within a Dockerfile ENTRYPOINT and CMD instructions.

1. Open the Dockerfile you created earlier in your preferred text editor.

2. Copy and paste the example Dockerfile contents into your Dockerfile, as shown below, and save it.

This Dockerfile creates a layer using the ubuntu:20.04 as a base image. It then tells Docker to invoke the echo command passing it the Hello world argument for both the Dockerfile CMD and ENTRYPOINT instructions using exec and shell form.

FROM ubuntu:20.04
# CMD Instruction
CMD ["echo", "Hello world"] # Exec Form
CMD echo "Hello world"      # Shell Form
# ENTRYPOINT Instruction
ENTRYPOINT ["echo", "Hello world"] # Exec Form
ENTRYPOINT echo "Hello world"      # Shell Form

3. While in the ~/docker directory, build the new image by running docker build and call it demo. The command below tags the image as demo and looks for a Dockerfile in the current working directory (.).

docker build -t demo .
Building a Docker image with docker build
Building a Docker image with docker build

4. Now, run a container using the image then run a Docker container based on the Docker image created earlier. You’ll now see that the container returns Hello world which came from the CMD instruction provided in the Dockerfile.

docker run -it demo
Running a Docker container with docker run
Running a Docker container with docker run

Using Variables in a Dockerfile

Sometimes you may not know the exact command-line arguments to pass to command ahead of time. The arguments you need to pass to a command are exposed only at runtime. Rather than statically assigning command arguments, you can capture and pass those arguments to commands with variables.

You can only use Dockerfile variables in shell form. Docker does not support variables in command invoked via exec form.

Open the Dockerfile in your preferred text editor again, replace everything inside with the following series of commands and save it.

You’ll notice this time, the Dockerfile uses environment variables and shown using ENV. In the example below, the Dockerfile is defining an environment variable called name with a value of friend. Once created, this environment variable is then referenced via $name.

When Docker runs a container based on this Dockerfile, it will invoke the echo command and pass the argument of Welcome, friend.

FROM ubuntu:20.04
ENV name friend

CMD echo "Welcome, $name"
# or
## ENTRYPOINT echo "Welcome, $name"

Now, create the Docker image and run the container again optionally providing a tag name of shellform. You’ll notice that Docker invoked the echo command and returned the expected output.

Building a Docker Image (shellform) and Running a Docker Container
Building a Docker Image (shellform) and Running a Docker Container

Combining Dockerfile ENTRYPOINT and CMD Instructions

Much of the time, you’ll be invoking startup commands either in CMD or ENTRYPOINT instruction. After all, you can invoke as many commands as you’d like using each method. But, you can also invoke a single command and “build onto it” using both instructions.

Building upon the previous examples, perhaps you have a Dockerfile that looks like the below example. As-is, if you create an image and run a container off of that image, Docker would invoke the echo command and return Hello.

FROM ubuntu:20.04
ENTRYPOINT ["echo", "Hello"]

Maybe you have another argument you’d like to pass to the echo command but not right away. Maybe you’d like to do that further down the Dockerfile. By calling the CMD instruction without a command, you can do so.

When you specify a command to run via the ENTRYPOINT instruction followed by the CMD instruction, Docker automatically assumes the value passed to CMD is an argument; not a command.

Now, add a CMD instruction reference without a command, just an argument called world, as shown below.

FROM ubuntu:20.04
ENTRYPOINT ["echo", "Hello"]
CMD ["world"]

Combining instructions should always be written in exec form due to its “array like” behavior of specifying values individually separated by commas vs all in one string.

After building the image and running the container from the image, you can see that instead of two lines of output (Hello and world), Docker only returns one meaning only a single echo command invocation.

Building a Docker Image (demo3) and Running a Docker Container
Building a Docker Image (demo3) and Running a Docker Container

Conclusion

You should now have a good understanding of running Docker container startup commands via both the CMD and ENTRYPOINT Dockerfile instructions. Each instruction is a bit different but accomplishes the same task and can even be used together.

Can you think of a scenario where you’d prefer using CMD over ENTRYPOINT to run a startup command?

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!