在Dockerfile中,CMD和ENTRYPOINT有什么区别?
在Dockerfiles中有两个看起来类似于我的命令: CMD和ENTRYPOINT 。 但是我猜他们之间有一个(微妙的)区别 – 否则,对于同样的事情,有两个命令是没有意义的。
该文档说明了CMD
CMD的主要目的是为正在执行的容器提供默认值。
和ENTRYPOINT :
一个ENTRYPOINT可以帮助你configuration一个你可以作为可执行文件运行的容器。
那么,这两个命令有什么区别呢?
Docker的默认入口点是/bin/sh -c但没有默认的命令。
当你像这样运行docker: docker run -i -t ubuntu bash入口点是默认的/bin/sh -c ,映像是ubuntu ,命令是bash 。
该命令通过入口点运行。 即,执行的实际内容是/bin/sh -c bash 。 这使得docker可以依靠shell的parsing器快速执行RUN 。 之后,人们要求能够定制这个,所以ENTRYPOINT和-entrypoint已经被引入。
在上面的例子中, ubuntu之后的所有东西都是命令,并传递给入口点。 当使用CMD指令时,就好像你在做docker run -i -t ubuntu <cmd> 。 <cmd>将是入口点的参数。
如果你input这个命令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相同的结果: docker run redisimg get key 。
ENTRYPOINT指定一个在容器启动时总是执行的命令。
CMD指定将被馈送到进入点的ENTRYPOINT 。
如果要制作专用于特定命令的图像,您将使用ENTRYPOINT ["/path/dedicated_command"]
否则,如果要为通用目的创build映像,则可以不指定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
现在,运行一个参数的图像将平实的论点:
$ 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/
是的,这是一个很好的问题。 我还没有完全理解,但是:
我知道ENTRYPOINT是正在执行的二进制文件。 你可以通过–entrypoint =“”来覆盖入口点。
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMD是容器的默认参数。 没有入口点,默认参数是执行的命令。 使用入口点,cmd作为parameter passing给入口点。 您可以使用入口点模拟命令。
# 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文件 ,
CMD和ENTRYPOINT指令都定义了运行容器时执行的命令。 有几条规则来描述他们的合作。
- Dockerfile应至less指定
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 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 ║ ╚════════════════════════════╩═════════════════════════════════════════════════╝
简而言之:
- CMD设置默认命令和/或参数,当docker容器运行时可以从命令行覆盖。
- ENTRYPOINT命令和参数不会被命令行覆盖。 相反,所有的命令行参数将被添加到ENTRYPOINT参数之后。
如果你需要更多的细节,或想看到不同的例子,有一个博客文章,综合比较CMD和ENTRYPOINT与大量的例子 – http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/
CMD和ENTRYPOINT之间的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之间的ENTRYPOINT :
docker run参数(如/bin/bash会覆盖我们在Dockerfile编写的任何CMD命令。
ENTRYPOINT不能在运行时使用普通命令(如docker run [args]重写。 ENTRYPOINT docker run [args]结尾处的docker run [args]作为参数提供给ENTRYPOINT 。 这样我们就可以创build一个container ,就像一个普通的二进制文件,比如ls 。
所以CMD可以作为默认参数到ENTRYPOINT ,然后我们可以覆盖[args]的CMD参数。
ENTRYPOINT可以用 – --entrypoint来覆盖。
在代码中的 EntryPoint函数的评论
// ENTRYPOINT / usr / sbin / nginx。
//将入口点(默认为sh -c)设置为/ usr / sbin / nginx。
//将接受CMD作为/ usr / sbin / nginx的参数。
另有参考文件
您可以使用ENTRYPOINT的execforms来设置相当稳定的默认命令和参数 ,然后使用CMD来设置更可能更改的其他默认值。
例:
FROM ubuntu:14.04.3 ENTRYPOINT ["/bin/ping"] CMD ["localhost", "-c", "2"]
构build :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将成为将要运行的命令。
被接受的答案在解释历史上是神话般的。 我觉得这张表很好地解释了“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 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是从第一个进程派生。
正如creack所说,CMD是第一个开发的。 那么进入点是为了更多的定制而开发的。 由于它们不是一起devise的,所以在CMD和进入点之间有一些function重叠,这经常使人们感到困惑。