The CMD
and ENTRYPOINT
instructions are two commonly confused Dockerfile
directives. Both have a role in determining the command which will run when the container starts.
The CMD
and ENTRYPOINT
can be overridden individually within each image. Effective use of these directives makes your container easier to use by shortening the length of commands you supply.
What Is The Entrypoint?
We’ll look at ENTRYPOINT
first as it’s processed before CMD
when starting a new container. The image’s entrypoint defines the process which will be run when the container starts.
Docker defaults the entrypoint to /bin/sh -c
. This means you’ll end up in a shell session when you start the container. For many containers, it’s more desirable to have a different process launch by default. You want headless services to start their workload straightaway.
Setting the ENTRYPOINT
directive in a Dockerfile
instructs Docker to run a specific command when the container starts. It will become the foreground process, instead of the default shell session.
ENTRYPOINT ["date"]
A container created with this Dockerfile
will run the date
command. As date
is not a long-living foreground process, the container will exit immediately afterwards.
Entrypoints must be executable binaries or scripts. Your container won’t start if you specify an invalid entrypoint. If you’re using a custom script, make sure it’s got the executable bit set. You can add execute permissions using chmod +x my-script.sh
.
Adding The Command (CMD)
The CMD
instruction is something of a misnomer. It provides default arguments for the command defined by ENTRYPOINT
.
ENTRYPOINT ["date"] CMD ["+%A"]
This example results in the container running date +%A
. The +%A
argument to date
displays the current day of the week (e.g. Monday
).
CMD
is designed to be overridden. docker run
lets you specify a different command for an individual container instance:
docker run my-image +%B
The default CMD
will be overridden with +%B
, causing the container to display the name of the current month. This works because the image’s entrypoint remains intact. The CMD
is always appended to the ENTRYPOINT
, so the final command becomes date +%B
.
You should use ENTRYPOINT
to define your container’s primary executable. Use CMD
to define default arguments for that executable. It will be overridden when the container is run with different arguments.
Entrypoint Overrides
You can force Docker to start an image using a custom entrypoint. Pass the --entrypoint
flag to docker run
:
docker run --entrypoint /bin/sh my-image
The entrypoint defined in the container’s image will be ignored in favour of the command you’ve specified. In our example, a shell session will be started, instead of the date
command.
Overriding entrypoints should be a rare occurrence. It can go against the image author’s intentions. Setting a custom entrypoint can be useful though, particularly when debugging. If a container’s misbehaving, overriding its entrypoint can grant you shell access you couldn’t otherwise obtain.
Which One To Use?
If you’re an image author, you should use ENTRYPOINT
when defining what your container will run. If you want to provide default arguments, but expect the user to override them, include CMD
too.
As an image user, you can normally stick to overriding CMD
. docker run
has transparent support for command overrides. Any arguments provided after the image name will be interpreted as the CMD
string for the container.
Entrypoint Modes: Shell or Exec
Docker actually supports two different forms of ENTRYPOINT
: exec mode and shell mode. Exec mode is characterised by the use of an array construct to specify parameters. In shell mode, the command is specified as one string.
# exec mode ENTRYPOINT ["binary", "--param", "--another-param"] # shell mode ENTRYPOINT binary --param --another-param
Using shell mode causes your binary to be executed as a subprocess of /bin/sh -c
. This gives your entrypoint access to environment variables defined by the shell.
Shell mode has tradeoffs though. You can’t use CMD
so users won’t be able to issue overrides. Arguments given to docker run
will be ignored; your container will always use the entrypoint as-is.
Because your binary runs within a shell, Docker lifecycle commands like docker stop
may work erratically or not at all. Docker will signal the shell to stop, instead of the process within. You can launch your process with exec
to avoid this.
ENTRYPOINT exec binary --param --another-param
Benefits of Docker’s Entrypoint Approach
Separating the entrypoint from its arguments helps you hide complexity in your containers. This is most beneficial when you’re creating utility containers to encapsulate CLI programs.
Set your CLI’s binary as the image’s entrypoint. This lets users interact without repeating the binary name in each command.
Consider if we packaged the above Dockerfile
as date:latest
:
# default entrypoint (/bin/sh -c) docker run date:latest date +%A # with `date` as the entrypoint docker run date:latest +%A`
Setting a custom entrypoint shortens commands and reduces repetition. The container becomes more specialised by invoking date
automatically. This creates a friendlier interface for your users.
Summary
Docker’s ENTRYPOINT
and CMD
instructions are a frequent source of confusion. Their naming masks their intended purposes.
Use ENTRYPOINT
to set the “command” that will execute when new containers start. You can define default arguments using CMD
. ENTRYPOINT
and CMD
are combined together to produce the container’s final command string.
When you use docker run
, Docker replaces the image’s default CMD
with the arguments you specify. If you need to override an image’s entrypoint, use the --entrypoint
flag.