CMD are two docker commands that sound interchangeable, but there are important differences that I’ll cover in this post. I suspect
CMD is probably the more familiar instruction, so I’ll go over what that does and how it differs from
Here’s the purpose of
CMD, taken straight from the docker manual:
The main purpose of ahttps://docs.docker.com/engine/reference/builder/#cmd
CMDis to provide defaults for an executing container.
If you start a container via
docker run or
docker start and you don’t supply any commands, the last CMD instruction is what gets executed. In most docker files, this effectively acts as “main” or … “entrypoint”. I put entrypoint in quotes both to distinguish it from the formal
ENTRYPOINT instruction and to show you why this naming is confusing!
Here’s an example of a dockerfile that runs the rails server using
# Use a base image with Ruby and Rails pre-installed FROM ruby:3.2 # Set the working directory inside the container WORKDIR /app # Copy the Gemfile and Gemfile.lock to the working directory COPY Gemfile Gemfile.lock ./ # Install dependencies RUN bundle install # Copy the rest of the application code to the working directory COPY . . # Set the default command to run the Rails server CMD ["rails", "server", "-b", "0.0.0.0"]Code language: PHP (php)
CMD does not create a new image layer, unlike commands like RUN. It does not do anything at build time. So when you run
docker build to create a docker image from a dockerfile,
rails server is not being executed. It purely a runtime (container runtime) construct. This interleaving of instructions in docker that are intended for difference stages of a container lifecycle is also a common source of confusion for beginner users of docker.
In practice, at least from my experience,
CMD is sufficient. I work on mostly web services and the vast majority of containers are running a server process of some kind using
CMD <start server> after the application dependencies are build. For most situations, this is enough and you never have to think about or even be aware of the existence of
Have a nice day.
Just kidding, okay lets go over
Here’s a rather confusing description on dockers website on what
ENTRYPOINTallows you to configure a container that will run as an executable.
CMD is to provide defaults for an executing container and
ENTRYPOINT is to configure a container that will run as an executable. That’s a little confusing because using
CMD sort of also allows you to run a container as an executable right? You start the container and something executes!
Here’s a simpler definition:
ENTRYPOINT is always run. It doesn’t matter what arguments you’re passing when running
ENTRYPOINT is never overwritten. If arguments are passed, those are appended to the end of what’s already specified in
Here’s an example of using the ENTRYPOINT instruction in a Dockerfile:
FROM ubuntu:latest ENTRYPOINT ["echo", "Hello, World!"]Code language: CSS (css)
In this example, the ENTRYPOINT is set to the command
echo "Hello, World!". When a container is created from this image and started, the message “Hello, World!” will be printed to the console. Running
docker run my-image "Welcome" would result in the message “Hello, World! Welcome” being printed.
Let’s take a look at an example using
CMD to demonstrate the override behavior:
FROM ubuntu:latest CMD ["echo", "Hello, World!"]Code language: CSS (css)
In this case, the CMD instruction specifies the default command as
echo "Hello, World!". However, if a user runs the container with a different command, the specified command will override the CMD instruction. For instance, running
docker run my-image "Welcome" would output “Welcome” instead of the default message “Hello, World!”. The entire command is overridden.
ENTRYPOINT can be used together in situations where you want
- A particular command to always execute (this is where
ENTRYPOINTcomes in handy) that cannot be overridden
- A set of default arguments for the
This offers some flexibility in how users of your image can provide custom arguments to alter the runtime behavior of your container. In cases where you don’t need that customization or where it’s perfectly fine for users to provide their own “entrypoints”, just use