在Dockerfiles中有两个看起来与我类似的命令:CMD
和ENTRYPOINT
.但是我猜它们之间存在着一种(微妙的?)差异 - 否则对于同样的事情来说两个命令就没有任何意义.
文档说明了 CMD
CMD的主要目的是为执行容器提供默认值.
并为ENTRYPOINT
:
ENTRYPOINT可帮助您配置可作为可执行文件运行的容器.
那么,这两个命令之间的区别是什么?
简而言之:
CMD设置默认命令和/或参数,当docker容器运行时,可以从命令行覆盖这些命令和/或参数.
ENTRYPOINT命令和参数不会从命令行覆盖.相反,所有命令行参数将在ENTRYPOINT参数之后添加.
如果您需要更多详细信息或想在示例中看到差异,可以通过大量示例全面比较CMD和ENTRYPOINT的博客文章 - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/
该ENTRYPOINT
规定将始终容器启动时执行的命令.
该CMD
指定参数,将被输送到ENTRYPOINT
.
如果您想制作专用于您将使用的特定命令的图像 ENTRYPOINT ["/path/dedicated_command"]
否则,如果您想为一般目的制作图像,您可以保留ENTRYPOINT
未指定并使用,CMD ["/path/dedicated_command"]
因为您可以通过提供参数来覆盖设置docker run
.
例如,如果您的Dockerfile是:
FROM debian:wheezy ENTRYPOINT ["/bin/ping"] CMD ["localhost"]
不带任何参数运行映像将ping 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
现在,使用参数运行图像将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 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
但是使用参数运行图像将运行参数:
docker run -it test bash root@e8bb7249b843:/#
有关更多详细信息,请参阅Brian DeHamer的这篇文章:https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
直觉 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]
被设置为参数入口点.通过这种方式,我们可以创建一个container
像普通二进制文件一样的东西ls
.
所以CMD可以作为ENTRYPOINT的默认参数,然后我们可以从[args]覆盖CMD args.
ENTRYPOINT可以覆盖--entrypoint
.
是的,这是个好问题.我还不完全理解它,但是:
我知道这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
据docker docs说,
CMD和ENTRYPOINT指令都定义了在运行容器时执行的命令.很少有规则描述他们的合作.
Dockerfile应至少指定一个
CMD
或多个ENTRYPOINT
命令.
ENTRYPOINT
应该在将容器用作可执行文件时定义.
CMD
应该用作定义ENTRYPOINT
命令的默认参数或在容器中执行ad-hoc命令的方法.
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 ? ????????????????????????????????????????????????????????????????????????????????
对代码中的 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将成为将要运行的命令.
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
.
我将以示例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
指令:
docker build -t custom_sleep . docker run custom_sleep # sleeps for 10 seconds and exits
该指令指定在容器启动时将运行的程序。
现在我们可以运行:
docker run custom_sleep sleep 20
那么默认值呢?好吧,你猜对了:
FROM ubuntu
ENTRYPOINT sleep
的ENTRYPOINT
是将要运行的程序,并通过在容器上的值将被附加到它。
该ENTRYPOINT
可通过指定覆盖--entrypoint
标志,后面是要使用新的切入点。
不是我的,我曾经看过提供此示例的教程
接受的答案很棒,可以解释历史.我发现这个表格从官方文档"CMD和ENTRYPOINT如何互动"中解释得非常好: