在Dockerfile中,有两个命令与我类似:CMD和ENTRYPOINT。但我想它们之间有一个(微妙的)区别——否则,对同一件事使用两个命令是没有意义的。
CMD的文档状态-
CMD的主要目的是为正在执行的容器提供默认值。
对于入口点:
ENTRYPOINT帮助您配置可以作为可执行文件运行的容器。
那么,这两个命令之间有什么区别?
在Dockerfile中,有两个命令与我类似:CMD和ENTRYPOINT。但我想它们之间有一个(微妙的)区别——否则,对同一件事使用两个命令是没有意义的。
CMD的文档状态-
CMD的主要目的是为正在执行的容器提供默认值。
对于入口点:
ENTRYPOINT帮助您配置可以作为可执行文件运行的容器。
那么,这两个命令之间有什么区别?
当前回答
根据docker文档,
CMD和ENTRYPOINT指令都定义执行什么命令当运行容器时。很少有规则描述合作。Dockerfile应至少指定CMD或ENTRYPOINT命令之一。将容器用作可执行文件时,应定义ENTRYPOINT。CMD应用作为ENTRYPOINT命令或在容器当使用可选参数运行容器时,CMD将被重写。
下表显示了对不同ENTRYPOINT/CMD组合执行的命令:
--无入口点
╔════════════════════════════╦═════════════════════════════╗
║ 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 ║
╚════════════════════════════╩═════════════════════════════╝
--入口点执行_入口p1_入口
╔════════════════════════════╦══════════════════════════════════╗
║ 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 ║
╚════════════════════════════╩══════════════════════════════════╝
--入口[“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 ║
╚════════════════════════════╩═════════════════════════════════════════════════╝
其他回答
Docker有一个默认入口点/bin/sh-c,但没有默认命令。
当你这样运行docker时:docker运行-i-t ubuntu bash入口点是默认的/bin/sh-c,图像是ubuntu,命令是bash。
该命令通过入口点运行。即,实际执行的是/bin/sh-cbash。这允许Docker依靠shell的解析器快速实现RUN。
后来,人们要求能够定制这个,所以引入了ENTRYPOINT和--ENTRYPOINT。
在上面的示例中,图像名称ubuntu之后的所有内容都是命令,并传递给入口点。当使用CMD指令时,它就像您在执行docker运行-i-t ubuntu<cmd>入口点的参数为<cmd>。
如果改为键入以下命令docker run-i-t ubuntu,也会得到相同的结果:bash shell将在容器中启动,因为在ubuntu Dockerfile中指定了默认CMD:CMD[“bash”]。
当一切都传递到入口点时,您可以从图像中获得非常好的行为@Jiri示例很好,它展示了如何将图像用作“二进制”。当使用[“/bin/cat”]作为入口点,然后执行docker运行img/etc/passwd时,您会发现,/etc/passwd是一个命令,并被传递到入口点,因此最终执行的结果只是/bin/cat/etc/passwd。
另一个示例是将任意cli作为入口点。例如,如果您有一个redis映像,而不是运行docker run redisig redis-H something-u to get key,您可以简单地使用ENTRYPOINT[“redis”,“-H”,“something”,“-u”,”toto“],然后像这样运行以获得相同的结果:docker run reisig get key。
ENTRYPOINT指定在容器启动时始终执行的命令。
CMD指定将被馈送到ENTRYPOINT的参数。
如果要使图像专用于特定命令,则将使用ENTRYPOINT[“/path/dessisted_command”]
否则,如果您想为通用目的生成图像,可以不指定ENTRYPOINT,使用CMD[“/path/dessisted_command”],因为您可以通过为docker运行提供参数来覆盖设置。
例如,如果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/
我将把我的答案作为一个例子,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
虽然这是可行的,但这不是一个好的解决方案,因为我们有一个冗余的“睡眠”命令。为什么冗余?因为容器的唯一目的是睡眠,所以必须显式指定睡眠命令有点尴尬。
现在,让我们尝试使用ENTRYPOINT指令:
FROM ubuntu
ENTRYPOINT sleep
此指令指定容器启动时将运行的程序。
现在我们可以运行:
docker run custom_sleep 20
默认值如何?嗯,你猜对了:
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]
ENTRYPOINT是将要运行的程序,传递给容器的值将附加到该程序。
可以通过指定--ENTRYPOINT标志,后跟要使用的新入口点来覆盖ENTRYPOINT。
不是我的,我曾经看过一个提供了这个例子的教程
是的,这是个好问题。我还不完全理解,但是:
我知道ENTRYPOINT是正在执行的二进制文件。可以通过--entrypoint=“”覆盖entrypoint。
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMD是容器的默认参数。如果没有入口点,默认参数是执行的命令。使用entrypoint,cmd将作为参数传递给entryppoint。您可以使用入口点模拟命令。
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
所以,主要优点是使用entrypoint可以将参数(cmd)传递给容器。要做到这一点,您需要同时使用:
# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]
and
docker build -t=cat .
那么您可以使用:
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default ENTRYPOINT
有一些很好的答案。我想通过每个文档的演示来解释
CMD定义容器的默认命令和/或参数。如果您需要用户可以轻松覆盖的默认命令,则最好使用CMD指令。如果Dockerfile有多个CMD,它只应用最后一个CMD中的指令。当您想要定义具有特定可执行文件的容器时,首选ENTRYPOINT。
除非添加--ENTRYPOINT标志,否则无法在启动容器时重写ENTRYPOINT。
命令
Docker文件
FROM centos:8.1.1911
CMD ["echo", "Hello Docker"]
运行结果
$ sudo docker run <image-id>
Hello Docker
$ sudo docker run <image-id> hostname # hostname is exec to override CMD
244be5006f32
入口点
Docker文件
FROM centos:8.1.1911
ENTRYPOINT ["echo", "Hello Docker"]
运行结果
$ sudo docker run <image-id>
Hello Docker
$ sudo docker run <image-id> hostname # hostname as parameter to exec
Hello Docker hostname
在许多情况下,将CMD和ENTRYPOINT结合起来是Docker容器的最佳解决方案。在这种情况下,可执行文件使用ENTRYPOINT定义,而CMD指定默认参数。
Docker文件
FROM centos:8.1.1911
ENTRYPOINT ["echo", "Hello"]
CMD ["Docker"]
运行结果
$ sudo docker run <image-id>
Hello Docker
$ sudo docker run <image-id> Ben
Hello Ben