在Dockerfile中,有两个命令与我类似:CMD和ENTRYPOINT。但我想它们之间有一个(微妙的)区别——否则,对同一件事使用两个命令是没有意义的。

CMD的文档状态-

CMD的主要目的是为正在执行的容器提供默认值。

对于入口点:

ENTRYPOINT帮助您配置可以作为可执行文件运行的容器。

那么,这两个命令之间有什么区别?


当前回答

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重写。

其他回答

是的,这是个好问题。我还不完全理解,但是:

我知道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

Dockerfile最佳实践的官方文档很好地解释了这些差异。Dockerfile最佳实践

CMD:

CMD指令应用于运行映像中包含的软件以及任何参数。CMD几乎应始终以CMD[“executable”,“param1”,“param2”…]的形式使用。因此,如果映像用于服务,例如Apache和Rails,则可以运行类似CMD[“apache2”,“-DFOREGROUND”]的命令。实际上,对于任何基于服务的图像,都建议使用这种形式的说明。

入口点:

ENTRYPOINT的最佳用法是设置映像的主命令,允许该映像像运行该命令一样运行(然后使用CMD作为默认标志)。

简而言之:

CMD设置默认命令和/或参数,当docker容器运行时,可以从命令行覆盖这些命令和/参数。ENTRYPOINT命令和参数不会从命令行覆盖。相反,所有命令行参数都将添加到ENTRYPOINT参数之后。

如果你需要更多的细节,或者想看到例子上的差异,有一篇博客文章将CMD和ENTRYPOINT与很多例子进行了全面比较https://codewithyury.com/docker-run-vs-cmd-vs-entrypoint/

大多数人在这里都解释得很好,所以我不会重复所有的答案。但为了得到一个好的感觉,我建议自己通过查看容器中的流程来测试它。

创建一个小型Dockerfile,格式如下:

FROM ubuntu:latest
CMD /bin/bash

构建它,用docker run-it-theimage运行它,并在容器中运行ps-eo-ppid、pid和args。使用以下选项时,将此输出与从ps接收的输出进行比较:

docker run-it theimage bash重建图像,但使用ENTRYPOINT/bin/bash并以两种方式运行使用CMD[“/bin/bash”]...

这样,您将很容易看到所有可能的方法之间的差异。