题 Dockerfile中CMD和ENTRYPOINT有什么区别?


在Dockerfiles中有两个看起来与我类似的命令: CMD 和 ENTRYPOINT。但是我猜它们之间有一个(微妙的?)区别 - 否则对于同样的事情有两个命令没有任何意义。

文档说明了 CMD

CMD的主要目的是为执行容器提供默认值。

并为 ENTRYPOINT

ENTRYPOINT可帮助您配置可作为可执行文件运行的容器。

那么,这两个命令之间的区别是什么?


1032
2018-02-04 13:04


起源


这篇博文有很好的描述差异以及它们如何一起使用: crosbymichael.com/dockerfile-best-practices.html。 - slm
那个!谢谢@slm。这是另一个非常类似的参考,可能有点更新: docs.docker.com/reference/builder/#entrypoint - Adam Monsen
那些引用来自哪里?你能提供链接吗? - Charlie Parker
一样令人困惑 和...之间的不同 ADD 和 COPY - Raedwald


答案:


Docker有一个默认的入口点 /bin/sh -c 但是没有默认命令。

当您像这样运行docker时: docker run -i -t ubuntu bash 入口点是默认值 /bin/sh -c,图像是 ubuntu 而命令是 bash

该命令通过入口点运行。即,实际执行的是 /bin/sh -c bash。这允许Docker实现 RUN 快速依赖shell的解析器。

后来,人们要求能够自定义这个,所以 ENTRYPOINT 和 --entrypoint 介绍了。

之后的一切 ubuntu 在上面的示例中是命令并传递给入口点。使用时 CMD 说明,就像你在做的那样 docker run -i -t ubuntu <cmd><cmd> 将是入口点的参数。

如果您改为输入此命令,也会得到相同的结果 docker run -i -t ubuntu。你仍然会在容器中启动一个bash shell,因为 ubuntu Dockerfile 指定了默认CMD: CMD ["bash"]

当所有内容都传递到入口点时,您可以从图像中获得非常好的行为。 @Jiri示例很好,它显示了如何将图像用作“二进制”。使用时 ["/bin/cat"] 作为入口点,然后做 docker run img /etc/passwd, 你懂了, /etc/passwd 是命令并传递给入口点,因此最终结果执行简单 /bin/cat /etc/passwd

另一个例子是将任何cli作为入口点。例如,如果您有redis图像,而不是运行 docker run redisimg redis -H something -u toto get key,你可以简单地拥有 ENTRYPOINT ["redis", "-H", "something", "-u", "toto"] 然后像这样运行相同的结果: docker run redisimg get key


1089
2018-02-04 22:34



我相信你的意思 docker run img /etc/passwd - kopiczko
一点也不。 ENTRYPOINT设置一个可以(但可以在运行时覆盖)的元数据,所以如果你没有改变任何东西,在启动容器后,结果将是相同的,但是,RUN将在构建时被执行,无论你是什么在运行时,它会在这里。 - creack
默认情况下没有 ENTRYPOINT;是否使用shell取决于使用的形式 CMD 命令(docs.docker.com/engine/reference/builder/#cmd)。 - Blaisorblade
多亏了这一点,历史背景帮助了很多,因为我正在努力记住关于被覆盖的内容和附加内容等看似神秘的规则。对于技术文档编写者而言,无处不在:帮助读者构建系统的心理模型,不要只列出事实和情景:-) - ashirley
这是一个很棒的答案。我认为Docker文档应该在一个名为的部分下添加它 CMD VS ENTRYPOINT。 - Tarik


ENTRYPOINT 指定在容器启动时始终执行的命令。

CMD 指定将被提供给的参数 ENTRYPOINT

如果您想制作专用于您将使用的特定命令的图像 ENTRYPOINT ["/path/dedicated_command"]

否则,如果你想制作一般用途的图像,你可以离开 ENTRYPOINT 未指定和使用 CMD ["/path/dedicated_command"] 因为您可以通过提供参数来覆盖设置 docker run

例如,如果您的Dockerfile是:

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

不带任何参数运行映像将ping本地主机:

$ 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

现在,使用参数运行图像将ping参数:

$ 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

为了比较,如果您的Dockerfile是:

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

不带任何参数运行映像将ping本地主机:

$ 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

但是使用参数运行图像将运行参数:

docker run -it test bash
root@e8bb7249b843:/#

有关更多详细信息,请参阅Brian DeHamer的这篇文章: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/


269
2017-12-12 22:17



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. 是一个很好的总结。 - Jingguo Yao
非常好的例子! - tgogos
很好的答案!这几乎就是这里定义的唯一答案 CDM 和 ENTERYPOINT 清楚而不仅仅是它如何工作或何时使用它。 - Stav Alfi
是的顺序 CMD 和 ENTRYPOINT 物? - OrangePot
@OrangePot我还没有测试改变顺序 ENTRYPOINT 和 CMD。也许你可以测试它并告诉每个人;) - Daishi


是的,这是一个很好的问题。我完全不了解它,但是:

我明白那个 ENTRYPOINT 是正在执行的二进制文件。您可以通过--entrypoint =“”覆盖入口点。

docker run -t -i --entrypoint="/bin/bash" ubuntu

CMD是容器的默认参数。如果没有入口点,则default参数是执行的命令。使用入口点,cmd作为参数传递给入口点。您可以使用入口点模拟命令。

# no entrypoint
docker run ubuntu /bin/cat /etc/passwd

# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd

因此,主要优点是使用入口点可以将参数(cmd)传递给容器。要实现此目的,您需要同时使用:

# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]

docker build -t=cat .

然后你可以使用:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT

138
2018-02-04 17:12



如果我想传递参数并指定一个入口点怎么办? - Blauhirn


根据 docker docs

CMD和ENTRYPOINT指令都定义了执行的命令   在运行容器时。描述他们的规则很少   合作。

  1. Dockerfile应该至少指定一个 CMD 要么 ENTRYPOINT 命令。
  2. ENTRYPOINT 应该在将容器用作可执行文件时定义。
  3. CMD 应该用作定义一个默认参数的方法 ENTRYPOINT 命令或用于执行ad-hoc命令   容器。
  4. CMD 在使用替代参数运行容器时将被覆盖。

下表显示 为不同的命令执行什么命令 ENTRYPOINT / CMD 组合

- 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 exec_cmd p1_cmd            ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd              ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd ║
╚════════════════════════════╩═══════════════════════════════════════════════════════════╝

- 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  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

109
2017-09-09 09:52



这是一个如此简单和重点的答案。 - crackerplace
什么是px_cmd和exec_entry?当他们在同一条执行线上时意味着什么?他们作为争论传递给对方?即使是 /bin/sh -c 参与 ? - Danielo515


简而言之:

  • CMD设置默认命令和/或参数,当docker容器运行时,可以从命令行覆盖这些命令和/或参数。
  • ENTRYPOINT命令和参数不会从命令行覆盖。相反,所有命令行参数将在ENTRYPOINT参数之后添加。

如果您需要更多详细信息或想在示例中看到差异,可以通过大量示例全面比较CMD和ENTRYPOINT的博客文章 - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/ 


27
2018-04-03 09:32





CMD和ENTRYPOINT之间的区别 通过直觉

  • ENTRYPOINT:容器启动时运行的命令。
  • CMD:在容器启动时运行的命令或ENTRYPOINT的参数(如果已指定)。

是的,它正在混淆。

运行docker run时,您可以覆盖其中任何一个。

CMD和ENTRYPOINT之间的区别 通过例子

docker run -it --rm yourcontainer /bin/bash            <-- /bin/bash overrides CMD
                                                       <-- /bin/bash does not override ENTRYPOINT
docker run -it --rm --entrypoint ls yourcontainer      <-- overrides ENTRYPOINT with ls
docker run -it --rm --entrypoint ls yourcontainer  -la  <-- overrides ENTRYPOINT with ls and overrides CMD with -la

更多关于差异 CMD 和 ENTRYPOINT

争论到 docker run 比如/ bin / bash会覆盖我们在Dockerfile中编写的任何CMD命令。

使用常规命令(例如)时,无法在运行时覆盖ENTRYPOINT docker run [args]。该 args 在......的最后 docker run [args] 作为ENTRYPOINT的参数提供。通过这种方式我们可以创建一个 container 这就像普通的二进制文件一样 ls

所以CMD可以作为ENTRYPOINT的默认参数,然后我们可以从[args]覆盖CMD args。

ENTRYPOINT可以覆盖 --entrypoint


16
2018-01-16 12:34





接受的答案很棒,可以解释历史。我发现这张表很好地解释了它 关于“CMD和ENTRYPOINT如何互动”的官方文件enter image description here


7
2018-05-31 07:12





关于入口点函数的评论

// ENTRYPOINT / usr / sbin / nginx。

//将入口点(默认为sh -c)设置为/ usr / sbin / nginx。

//将接受CMD作为/ usr / sbin / nginx的参数。

文件的另一个参考

您可以使用ENTRYPOINT的exec形式进行设置 相当稳定的默认命令和参数 然后使用CMD设置更有可能更改的其他默认值。

例:

FROM ubuntu:14.04.3
ENTRYPOINT ["/bin/ping"]
CMD ["localhost", "-c", "2"]

建立:sudo docker build -t ent_cmd。

CMD arguments are easy to override.

NO argument (sudo docker -it ent_cmd)                :  ping localhost 
argument    (sudo docker run -it ent_cmd google.com) :  ping google.com

To override EntryPoint argument, you need to supply entrypoint
sudo docker run -it --entrypoint="/bin/bash" ent_cmdd

P.S: 在EntryPoint存在的情况下,CMD将保留为EntryPoint提供的参数。 在没有EntryPoint的情况下,CMD将成为将要运行的命令。


5
2018-01-16 07:32





CMD:

  • CMD ["executable","param1","param2"]["executable","param1","param2"] 是第一个过程。
  • CMD command param1 param2/bin/sh -c CMD command param1 param2 是第一个过程。 CMD command param1 param2 从第一个进程分叉。
  • CMD ["param1","param2"]:此表单用于提供默认参数 ENTRYPOINT

ENTRYPOINT(以下列表不考虑CMD和ENTRYPOINT一起使用的情况):

  • ENTRYPOINT ["executable", "param1", "param2"]["executable", "param1", "param2"] 是第一个过程。
  • ENTRYPOINT command param1 param2/bin/sh -c command param1 param2 是第一个过程。 command param1 param2 从第一个进程分叉。

creack 说,CMD是第一个开发的。然后开发了ENTRYPOINT以进行更多定制。由于它们不是一起设计的,因此CMD和ENTRYPOINT之间存在一些功能重叠,这常常让人感到困惑。


1
2018-01-05 06:42