Categories
docker

What is the difference between CMD and ENTRYPOINT in a Dockerfile?

2411

In Dockerfiles there are two commands that look similar to me: CMD and ENTRYPOINT. But I guess that there is a (subtle?) difference between them – otherwise it would not make any sense to have two commands for the very same thing.

The documentation states for CMD

The main purpose of a CMD is to provide defaults for an executing container.

and for ENTRYPOINT:

An ENTRYPOINT helps you to configure a container that you can run as an executable.

So, what’s the difference between those two commands?

6

2315

Docker has a default entrypoint which is /bin/sh -c but does not have a default command.

When you run docker like this:
docker run -i -t ubuntu bash
the entrypoint is the default /bin/sh -c, the image is ubuntu and the command is bash.

The command is run via the entrypoint. i.e., the actual thing that gets executed is /bin/sh -c bash. This allowed Docker to implement RUN quickly by relying on the shell’s parser.

Later on, people asked to be able to customize this, so ENTRYPOINT and --entrypoint were introduced.

Everything after the image name, ubuntu in the example above, is the command and is passed to the entrypoint. When using the CMD instruction, it is exactly as if you were executing
docker run -i -t ubuntu <cmd>
The parameter of the entrypoint is <cmd>.

You will also get the same result if you instead type this command docker run -i -t ubuntu: a bash shell will start in the container because in the ubuntu Dockerfile a default CMD is specified:
CMD ["bash"].

As everything is passed to the entrypoint, you can have a very nice behavior from your images. @Jiri example is good, it shows how to use an image as a “binary”. When using ["/bin/cat"] as entrypoint and then doing docker run img /etc/passwd, you get it, /etc/passwd is the command and is passed to the entrypoint so the end result execution is simply /bin/cat /etc/passwd.

Another example would be to have any cli as entrypoint. For instance, if you have a redis image, instead of running docker run redisimg redis -H something -u toto get key, you can simply have ENTRYPOINT ["redis", "-H", "something", "-u", "toto"] and then run like this for the same result: docker run redisimg get key.

16

  • 5

    Not at all. ENTRYPOINT sets a metadata that can (but can be overridden) at runtime, so if you don’t change anything, after starting your container, the result will be the same, however, RUN will be exectuted at build time and no matter what you do at runtime, it will be here.

    – creack

    Dec 29, 2015 at 15:07

  • 15

    By default there’s no ENTRYPOINT; whether a shell is used depends on the used form of the CMD command (docs.docker.com/engine/reference/builder/#cmd).

    Jan 13, 2016 at 22:29

  • 60

    Thanks for this, the historical context helps a lot as I was struggling to remember the seemingly arcane rules about what is overridden and what is appended etc. A useful point for technical documentation writers everywhere: help the reader build a mental model of the system, don’t just list facts and scenarios 🙂

    – ashirley

    May 9, 2016 at 13:32

  • 162

    This is a fabulous answer. I think Docker documentation should add this under a section called CMD vs ENTRYPOINT.

    – Tarik

    Dec 28, 2016 at 19:37

  • 10

    @Webman No. They are two different instructions. If they both exist, CMD would be treated as ENTRYPOINT’s parameters.

    – Light.G

    Sep 24, 2018 at 16:14

995

The ENTRYPOINT specifies a command that will always be executed when the container starts.

The CMD specifies arguments that will be fed to the ENTRYPOINT.

If you want to make an image dedicated to a specific command you will use ENTRYPOINT ["/path/dedicated_command"]

Otherwise, if you want to make an image for general purpose, you can leave ENTRYPOINT unspecified and use CMD ["/path/dedicated_command"] as you will be able to override the setting by supplying arguments to docker run.

For example, if your Dockerfile is:

FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]

Running the image without any argument will ping the localhost:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms

Now, running the image with an argument will ping the argument:

$ docker run -it test google.com
PING google.com (173.194.45.70): 48 data bytes
56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
^C--- google.com ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms

For comparison, if your Dockerfile is:

FROM debian:wheezy
CMD ["/bin/ping", "localhost"]

Running the image without any argument will ping the localhost:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms

But running the image with an argument will run the argument:

docker run -it test bash
[email protected]:/#

See this article from Brian DeHamer for even more details:
https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/

6

  • 397

    The ENTRYPOINT specifies a command that will always be executed when the container starts. The CMD specifies arguments that will be fed to the ENTRYPOINT. is a good to-the-point summary.

    Jan 4, 2016 at 14:26


  • 16

    ENTRYPOINT can also be overridden using –entrypoint flag. for e.g docker run -it –entrypoint bash test

    Sep 4, 2018 at 16:15


  • 7

    I like your examples, it really helpful!

    Aug 16, 2019 at 4:53

  • 3

    @Jingguo Yao : What if CMD contains a command such as – CMD [“nginx”,”-g”,”daemon”,”off”]? Would it be chained?

    – KMC

    Aug 29, 2019 at 16:00

  • 4

    ENTRYPOINT is often pointed to an entry script (rather than a command) that can do many useful things like: verify requirements before execution (like readyness probes on dependencies); proxy/wrap a command to validate it, or to change the executing user, or to change files’ owner (for example when mounting hostPath on Minikube, by default files get overridden with UID/GID 1000:1000), etc..

    Nov 9, 2020 at 20:56


353

According to docker docs,

Both CMD and ENTRYPOINT instructions define what command gets executed
when running a container. There are few rules that describe their
co-operation.

  1. Dockerfile should specify at least one of CMD or ENTRYPOINT commands.
  2. ENTRYPOINT should be defined when using the container as an executable.
  3. CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a
    container.
  4. CMD will be overridden when running the container with alternative arguments.

The tables below shows what command is executed for different ENTRYPOINT / CMD combinations:

No ENTRYPOINT

╔════════════════════════════╦═════════════════════════════╗
║ No CMD                     ║ error, not allowed          ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD ["exec_cmd", "p1_cmd"] ║ exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"]   ║ p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════╝

ENTRYPOINT exec_entry p1_entry

╔════════════════════════════╦══════════════════════════════════╗
║ No CMD                     ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD ["exec_cmd", "p1_cmd"] ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"]   ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry   ║
╚════════════════════════════╩══════════════════════════════════╝

ENTRYPOINT ["exec_entry", "p1_entry"]

╔════════════════════════════╦═════════════════════════════════════════════════╗
║ No CMD                     ║ exec_entry p1_entry                             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD ["exec_cmd", "p1_cmd"] ║ exec_entry p1_entry exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"]   ║ exec_entry p1_entry p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

10

  • 1

    What are px_cmd and exec_entry ? What does mean when they are on the same execution line ? They are passed as argument to each other ? Even when the /bin/sh -c is involved ?

    Nov 7, 2017 at 15:02

  • 2

    @Danielo515 Both ‘px_cmd’ and ‘exec_entry’ are just dummy strings here. You may just notice that /bin/sh -c would be added to CMD as prefix while CMD written in executable syntax(not list syntax).

    – Light.G

    Sep 26, 2018 at 11:25

  • 3

    ENTRYPOINT exec_entry p1_ent was wrongly explained. The shell form prevents any CMD or run command line arguments from being used – docs.docker.com/engine/reference/builder/#entrypoint

    Nov 18, 2019 at 10:40

  • 2

    @MariuszMiesiak it’s now updated. Thanks for your feedback.

    Nov 22, 2019 at 5:28

  • 3

    BTW: this answer definitely should be the accepted answer! (while the current one claims that “Docker has a default entrypoint which is /bin/sh -c“…)

    – ErikMD

    Jan 12, 2021 at 20:13