在Dockerfile中,有两个命令与我类似:CMD和ENTRYPOINT。但我想它们之间有一个(微妙的)区别——否则,对同一件事使用两个命令是没有意义的。
CMD的文档状态-
CMD的主要目的是为正在执行的容器提供默认值。
对于入口点:
ENTRYPOINT帮助您配置可以作为可执行文件运行的容器。
那么,这两个命令之间有什么区别?
在Dockerfile中,有两个命令与我类似:CMD和ENTRYPOINT。但我想它们之间有一个(微妙的)区别——否则,对同一件事使用两个命令是没有意义的。
CMD的文档状态-
CMD的主要目的是为正在执行的容器提供默认值。
对于入口点:
ENTRYPOINT帮助您配置可以作为可执行文件运行的容器。
那么,这两个命令之间有什么区别?
当前回答
Dockerfile最佳实践的官方文档很好地解释了这些差异。Dockerfile最佳实践
CMD:
CMD指令应用于运行映像中包含的软件以及任何参数。CMD几乎应始终以CMD[“executable”,“param1”,“param2”…]的形式使用。因此,如果映像用于服务,例如Apache和Rails,则可以运行类似CMD[“apache2”,“-DFOREGROUND”]的命令。实际上,对于任何基于服务的图像,都建议使用这种形式的说明。
入口点:
ENTRYPOINT的最佳用法是设置映像的主命令,允许该映像像运行该命令一样运行(然后使用CMD作为默认标志)。
其他回答
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/
Dockerfile文件中提到的CMD命令可以通过docker run命令覆盖,而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
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]等正常命令覆盖。docker运行结束时的args[args]作为ENTRYPOINT的参数提供。通过这种方式,我们可以创建一个像ls这样的普通二进制文件的容器。
因此,CMD可以作为ENTRYPOINT的默认参数,然后我们可以从[args]重写CMD参数。
ENTRYPOINT可以用--ENTRYPOINT重写。
通过从头开始重建OS映像(只需从头开始编写,并在dockerfile中使用COPY复制最小的文件系统),我了解到,
如果没有在dockerfile中指定ENTRYPOINT和CMD,docker将使用
/bin/sh -c
作为默认ENTRYPOINT,如果在docker文件中定义CMD或在运行容器时传递命令行参数(这将覆盖已定义的CMD),则将采用CMD。
假设您传递一个参数(或在dockerfile中定义CMD)ls,那么它将被馈送到ENTRYPOINT。即,
/bin/sh -c ls
/bin/sh-c将运行传递给它的任何参数。您将获得“ls”命令的输出,然后容器将退出。
ubuntu映像没有显式定义ENTRYPOINT,因此docker将使用/bin/sh-c,但包含CMD定义,即bash运行容器的以下命令,
docker container run -it ubuntu
Docker实际上使用ENTRYPOINT作为/bin/sh-c,然后使用bash为其提供数据最终运行的是
/bin/sh -c bash
它启动交互式bash终端(仅当如上所述指定了-i标志并可选地指定了-t以获得类似本地终端的体验时)
当您通过命令行提供参数时,bash将被替换为您传递的任何内容,输出将根据该内容,即
/bin/sh -c passed_argument
您可以定义自定义ENTRYPOINT,它将覆盖默认ENTRYPOINT,但随后需要相应地使用CMD。
对于dockerfile中的RUN命令,它不考虑定义的ENTRYPOINT和CMD,而是运行指定的命令,因为它们被提供给中间容器中的交互式bash终端