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


1695

在Dockerfiles中,有两个与我相似的命令:CMDENTRYPOINT。但是我想它们之间有一个(细微的?)区别-否则,对于同一件事有两个命令是没有任何意义的。

文档说明 CMD

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

和为ENTRYPOINT

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

那么,这两个命令有什么区别?


12
这篇博客文章很好地描述了差异以及如何将它们一起使用:crosbymichael.com/dockerfile-best-practices.html
slm 2015年

2
^那!谢谢@slm。这是另一个非常相似的参考,可能需要更新一些:docs.docker.com/reference/builder/#entrypoint
Adam Monsen


1
此链接提供了RUN,CMD和ENTRYPOINT之间的区别:goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi

不过请注意CMD,并ENTRYPOINT都具有不同的形式被写入,EXEC外壳的形式。因此,请帮自己一个忙,并根据所使用的形式了解行为上的细微差别。然后阅读docs.docker.com/engine/reference/builder/…
Jaime Hablutzel

Answers:


1733

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。由于ubuntu Dockerfile指定了默认CMD ,因此您仍将在容器中启动bash shell :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


3
一点也不。ENTRYPOINT设置的元数据可以在运行时(但可以覆盖),因此,如果您不进行任何更改,则在启动容器后,结果将是相同的,但是无论构建了什么,RUN都会在构建时执行在运行时执行,它将在这里。
creack

8
默认情况下,有没有ENTRYPOINT; 是否使用外壳取决于CMD命令的使用形式(docs.docker.com/engine/reference/builder/#cmd)。
Blaisorblade '16

19
多亏了这一点,历史背景对我很有帮助,因为我一直在努力记住关于哪些内容被覆盖和附加的看似神秘的规则。对于各地的技术文档编写者来说,这是一个有用的观点:帮助读者建立系统的思维模型,不要只列出事实和场景:-)
阿希尔(Ashirley)'16

84
这是一个了不起的答案。我认为Docker文档应该在CMDvs 一节下添加它ENTRYPOINT
塔里克

5
@Webman号。它们是两个不同的指令。如果它们都存在,则CMD将被视为ENTRYPOINT的参数。
Light.G

626

ENTRYPOINT指定容器启动时就一定会执行的命令。

CMD指定参数,将被输送到ENTRYPOINT

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

否则,如果您要制作通用图像,可以不ENTRYPOINT指定使用CMD ["/path/dedicated_command"]因为您可以通过向提供参数来覆盖设置docker run

例如,如果您的Dockerfile是:

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

运行不带任何参数的映像将对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"]

运行不带任何参数的映像将对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/


218
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.是一个很好的要点总结。
姚敬国

1
也可以使用--entrypoint标志来覆盖ENTRYPOINT。用于例如docker run -it --entrypoint bash测试
seenimurugan

2
我喜欢您的例子,真的很有帮助!
周江

2
@Jingguo Yao:如果CMD包含诸如-CMD [“ nginx”,“-g”,“ daemon”,“ off”]的命令怎么办?会被锁起来吗?
KMC

@KMC CMD是ENTRYPOINT的默认参数,您可以在运行图像时通过传递新的arg来覆盖它。
MGP

237

根据docker docs

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

  1. Dockerfile应该至少指定CMDENTRYPOINT命令之一。
  2. ENTRYPOINT 使用容器作为可执行文件时应定义。
  3. CMD应该用作ENTRYPOINT在容器中定义命令或执行临时命令的默认参数的方式。
  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   ║
╟────────────────────────────╫──────────────────────────────────╢
║ 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  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

什么是px_cmd和exec_entry?它们在同一执行行上是什么意思?它们作为论点彼此传递?即使/bin/sh -c涉及到?
Danielo515 '17

1
@ Danielo515'px_cmd'和'exec_entry'都只是虚拟字符串。您可能只是注意到,/bin/sh -c当CMD以可执行语法(而非列表语法)编写时,将作为前缀添加到CMD。
Light.G

1
@royki如果用户指定参数搬运工跑那么他们将覆盖CMD指定的默认。
donrondadon

2
ENTRYPOINT exec_entry p1_ent被错误地解释了。shell形式可防止使用任何CMD或运行命令行参数-docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak

1
@MariuszMiesiak现在已更新。感谢您的反馈意见。
拉法夫·塔欣

169

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

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

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

CMD是容器的默认参数。没有入口点,默认参数是执行的命令。使用入口点,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

@Blauhirn在您的情况下,必须以列表语法向CMD添加参数,并确保分隔的入口点可以解析CMD中的参数。通常,我在入口点添加“ -h”参数。然后我可以执行docker run image_name -h以显示该图像的一些帮助信息。
Light.G

1
这是最简单明了的答案。
Eric Wang

44

通过直觉,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的覆盖任何CMD命令我们Dockerfile写道。

ENTRYPOINT无法在运行时使用常规命令覆盖,例如docker run [args]。所述args在端部docker run [args]被设置为参数入口点。这样,我们可以创建container类似于普通二进制文件(例如)的ls

因此,CMD可以用作ENTRYPOINT的默认参数,然后我们可以从[args]中覆盖CMD args。

可以用ENTRYPOINT覆盖--entrypoint


38

简而言之:

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

如果您需要了解更多信息或想看到的例子差,有一个博客贴子,综合比较CMD和入口点,有很多的例子- http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/


21

我将回答作为示例1这可能有助于您更好地理解差异。

假设我们要创建一个在启动时始终运行sleep命令的映像。我们将创建自己的图像并指定一个新命令:

FROM ubuntu
CMD sleep 10

现在,我们构建图像:

docker build -t custom_sleep .
docker run custom_sleep
# sleeps for 10 seconds and exits

如果要更改秒数怎么办?我们将不得不更改Dockerfile值,因为该值在此处进行了硬编码,或者通过提供其他命令来覆盖该命令:

docker run custom_sleep sleep 20

尽管此方法有效,但这不是一个好的解决方案,因为我们有一个多余的“ sleep”命令(容器的目的是sleep,因此必须显式指定sleep命令不是一个好习惯)。

现在让我们尝试使用以下ENTRYPOINT指令:

FROM ubuntu
ENTRYPOINT sleep

该指令指定了容器启动时将要运行的程序

现在我们可以运行:

docker run custom_sleep 20

那么默认值呢?好吧,你猜对了:

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

ENTRYPOINT是将要运行的程序,并通过在容器上的值将被附加到它。

ENTRYPOINT可通过指定覆盖--entrypoint标志,后面是要使用新的切入点。

不是我的,我曾经看过提供此示例的教程


1
这里是该教程的链接:youtu.be/OYbEWUbmk90。这可能对将来的用户有用。
ChiPlusPlus


7

代码中对EntryPoint函数的注释

// 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

ps:在存在EntryPoint的情况下,CMD将保存要馈送到EntryPoint的参数。在缺少EntryPoint的情况下,将运行CMD。


3

CMDDockerfile文件中提到的docker run命令ENTRYPOINT可以通过命令覆盖,而不能。


4
docker run --help命令另有说明:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv

3

我已阅读了所有答案,并希望总结一下以便更好地理解,如下所示:

首先,在容器中执行的整个命令包括两部分: 命令参数

  • ENTRYPOINT定义启动容器(用于命令)时调用的可执行文件

  • CMD指定传递给ENTRYPOINT的参数(用于参数)

Kubernetes In Action》一书中对此进行了重要说明。(第7章)

尽管您可以使用CMD指令指定要在运行映像时执行的命令,但正确的方法是通过ENTRYPOINT指令执行此操作,并且仅在要定义默认参数时才指定CMD

您还可以阅读文章很好的解释以简单的方式


2

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之间存在一些功能重叠,这通常会使人们感到困惑。


2

大多数人在这里都很好地解释了这一点,所以我不会重复所有的答案。但是要获得良好的感觉,我建议您通过查看容器中的过程自己进行测试。

创建以下形式的微型Dockerfile:

FROM ubuntu:latest
CMD /bin/bash

编译,运行docker run -it theimageps -eo ppid,pid,args在容器中运行。使用以下命令时,将此输出与您从ps接收的输出进行比较:

  • docker run -it theimage bash
  • 重建图像,但同时以ENTRYPOINT /bin/bash两种方式运行
  • 使用 CMD ["/bin/bash"]
  • ...

这样,您将轻松地自己了解所有可能方法之间的差异。


0

Dockerfile最佳实践的官方文档在解释这些差异方面做得很好。 Dockerfile最佳实践

CMD:

应该使用CMD指令来运行映像所包含的软件以及所有参数。CMD几乎应始终以的形式使用CMD ["executable", "param1", "param2"…]。因此,如果映像用于服务(例如Apache和Rails),则将运行CMD ["apache2","-DFOREGROUND"]。实际上,对于任何基于服务的映像都建议使用这种形式的指令。

入口点:

ENTRYPOINT的最佳用途是设置映像的主命令,从而使该映像像该命令一样运行(然后使用CMD作为默认标志)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.