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
CMD instructions, you can run as many startup commands as you’d like.
In this tutorial, you’ll learn how to use the
CMD instructions to run startup commands in a Dockerfile and understand the differences between them.
Table of Contents
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.
4. Finally, add the following content into the Dockerfile
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
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 .
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
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
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.
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
ENTRYPOINT instructions using
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 .
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
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
shellform. Docker does not support variables in command invoked via
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
When Docker runs a container based on this Dockerfile, it will invoke the
echo command and pass the argument of
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.
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
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
ENTRYPOINTinstruction followed by the
CMDinstruction, Docker automatically assumes the value passed to
CMDis 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 (
world), Docker only returns one meaning only a single
echo command invocation.
You should now have a good understanding of running Docker container startup commands via both the
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
ENTRYPOINT to run a startup command?
More from Adam The Automator & Friends