What is the difference between CMD and ENTRYPOINT in a Dockerfile?
有两个命令在dockerfiles看起来类似于:
在文档中的
The main purpose of a CMD is to provide defaults for an executing container.
和
An ENTRYPOINT helps you to configure a container that you can run as an executable.
那么,什么是"两个命令之间的差异如何?
Docker有一个默认入口点,它是
当你像这样运行Docker时:
命令通过入口点运行。即实际执行的是
后来,人们要求能够定制它,所以引入了
在上面的示例中,
如果您改为键入该命令
当所有东西都传递到入口点时,您可以从图像中获得非常好的行为。@Jiri示例很好,它演示了如何将图像用作"二进制"。当使用
另一个例子是使用任何CLI作为入口点。例如,如果您有一个redis映像,而不是运行
如果您想制作一个专用于特定命令的图像,您将使用
否则,如果您想制作一个通用的图像,您可以不指定
例如,如果dockerfile是:
1 2 3 | FROM debian:wheezy ENTRYPOINT ["/bin/ping"] CMD ["localhost"] |
不带任何参数运行映像将ping本地主机:
1 2 3 4 5 6 7 8 | $ 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该参数:
1 2 3 4 5 6 7 8 | $ 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是:
1 2 | FROM debian:wheezy CMD ["/bin/ping","localhost"] |
不带任何参数运行映像将ping本地主机:
1 2 3 4 5 6 7 8 | $ 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 |
但是使用参数运行图像将运行参数:
1 2 | docker run -it test bash root@e8bb7249b843:/# |
更多详细信息,请参阅Brian Dehamer的这篇文章:https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
根据Docker文件,
Both CMD and ENTRYPOINT instructions define what command gets executed
when running a container. There are few rules that describe their
co-operation.Dockerfile should specify at least one of CMD orENTRYPOINT commands.ENTRYPOINT should be defined when using the container as an executable.CMD should be used as a way of defining default arguments for anENTRYPOINT command or for executing an ad-hoc command in a
container.CMD will be overridden when running the container with alternative arguments.
下表显示了针对不同
--埃多克斯1〔2〕
1 2 3 4 5 6 7 8 9 | ╔════════════════════════════╦═════════════════════════════╗ ║ 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 ║ ╚════════════════════════════╩═════════════════════════════╝ |
--埃多克斯1〔3〕
1 2 3 4 5 6 7 8 9 | ╔════════════════════════════╦═══════════════════════════════════════════════════════════╗ ║ 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 ║ ╚════════════════════════════╩═══════════════════════════════════════════════════════════╝ |
--江户十一〔四〕号
1 2 3 4 5 6 7 8 9 | ╔════════════════════════════╦═════════════════════════════════════════════════╗ ║ 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 ║ ╚════════════════════════════╩═════════════════════════════════════════════════╝ |
是的,这是个好问题。我还不完全理解,但是:
我知道
1 | docker run -t -i --entrypoint="/bin/bash" ubuntu |
cmd是容器的默认参数。如果没有入口点,默认参数是执行的命令。使用entrypoint,命令作为参数传递给entrypoint。可以使用入口点模拟命令。
1 2 3 4 5 | # no entrypoint docker run ubuntu /bin/cat /etc/passwd # with entry point, emulating cat command docker run --entrypoint="/bin/cat" ubuntu /etc/passwd |
所以,主要的优点是使用入口点可以将参数(cmd)传递到容器中。要实现这一点,您需要同时使用以下两种方法:
1 2 3 | # Dockerfile FROM ubuntu ENTRYPOINT ["/bin/cat"] |
和
1 | docker build -t=cat . |
然后您可以使用:
1 2 3 4 5 | docker run cat /etc/passwd # ^^^^^^^^^^^ # CMD # ^^^ # image (tag)- using the default ENTRYPOINT |
Cmd和入口点的直觉差异:
- entrypoint:容器启动时运行的命令。
- 命令:当容器启动时运行的命令,或者如果指定了入口点的参数。
是的,它混淆了。
运行docker run时,可以覆盖其中任何一个。
命令和入口点之间的区别(通过示例):
1 2 3 4 | 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 |
更多关于
entrypoint不能在运行时被正常命令(如
因此,cmd可以作为入口点的默认参数,然后我们可以从[args]重写cmd参数。
入口点可以用
简而言之:
- cmd设置默认命令和/或参数,当docker容器运行时,可以从命令行覆盖这些参数。
- 入口点命令和参数不会从命令行覆盖。相反,所有命令行参数都将添加在入口点参数之后。
如果你需要更多的细节或者想看看例子的不同,有一篇博文综合比较了cmd和entrypoint和很多例子-http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/
公认的答案在解释历史方面是极好的。我发现这张表很好地解释了来自官方文档关于"cmd和entrypoint如何交互"的内容:
代码中入口点函数的注释
// ENTRYPOINT /usr/sbin/nginx.
// Set the entrypoint (which defaults to sh -c) to /usr/sbin/nginx.
// Will accept the CMD as the arguments to /usr/sbin/nginx.
来自文档的另一个引用
You can use the exec form of ENTRYPOINT to set fairly stable default commands and arguments and then use CMD to set additional defaults that are more likely to be changed.
例子:
1 2 3 | FROM ubuntu:14.04.3 ENTRYPOINT ["/bin/ping"] CMD ["localhost","-c","2"] |
构建:sudo docker build-t ent_cmd。
1 2 3 4 | 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 |
.
1 2 | To override EntryPoint argument, you need to supply entrypoint sudo docker run -it --entrypoint="/bin/bash" ent_cmdd |
附笔:在入口点存在的情况下,cmd将持有fed到入口点的参数。在缺少入口点的情况下,将运行命令cmd。
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 提供默认参数。
入口点(以下列表不考虑将cmd和入口点一起使用的情况):
ENTRYPOINT ["executable","param1","param2"] :["executable","param1","param2"] 是第一道工序。ENTRYPOINT command param1 param2 :/bin/sh -c command param1 param2 是第一道工序。command param1 param2 是从第一个过程分叉出来的。
正如克里克所说,命令是先开发的。然后开发了入口点,以便进行更多的定制。由于它们不是一起设计的,所以在cmd和entrypoint之间有一些功能重叠,这常常使人感到困惑。
大多数人在这里解释得很好,所以我不会重复所有的答案。但是为了获得一种良好的感觉,我建议通过查看容器中的流程来自己测试它。
创建表单的一个小文件:
1 2 | FROM ubuntu:latest CMD /bin/bash |
构建它,使用
docker run -it theimage bash - 重建图像,但使用
ENTRYPOINT /bin/bash 并以两种方式运行 - 使用
CMD ["/bin/bash"] 。 - …
这样你就可以很容易地看到所有可能的方法之间的差异。