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

CMD的文档状态-

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

对于入口点:

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终端

其他回答

我将把我的答案作为一个例子,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。

不是我的,我曾经看过一个提供了这个例子的教程

这个公认的答案在解释历史方面非常棒。我发现这张表很好地解释了“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"]

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

附笔:在存在EntryPoint的情况下,CMD将保存要馈送到EntryPoint的参数。如果没有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”]...

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