ENTRYPOINT和CMD

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ENTRYPOINT和CMD相关的知识,希望对你有一定的参考价值。

参考技术A

原文: https://zhuanlan.zhihu.com/p/30555962

从根本上说, ENTRYPOINT和CMD都是让用户指定一个可执行程序, 这个可执行程序在container启动后自动启动. 实际上, 如果你想让自己制作的镜像自动运行程序(不需要在docker run后面添加命令行指定运行的命令), 你必须在Dockerfile里面, 使用ENTRYPOINT或者CMD命令

比如执行运行一个没有调用ENTRYPOINT或者CMD的docker镜像, 一定返回错误

大部分Linu发行版的基础镜像里面调用CMD命令, 指定容器启动后执行/bin/sh或/bin/bash. 这样镜像启动默认进入交互式的shell

[图片上传失败...(image-10e0a4-1649389009146)]

译注: 3个不同的Linux镜像(ubuntu, busybox, debian)都在Dockerfile的最后调用 CMD \'/bin/bash\'

启动Linux发行版的基础container后, 默认调用shell程序, 符合大多数人的习惯.

但是, 作为开发者, 你希望在docker镜像启动后, 自动运行其他程序. 所以, 你需要用CMD或者ENTRYPOINT命令显式地指定具体的命令.

在写Dockerfile时, ENTRYPOINT或者CMD命令会自动覆盖之前的ENTRYPOINT或者CMD命令.

在docker镜像运行时, 用户也可以在命令指定具体命令, 覆盖在Dockerfile里的命令.

比如, 我们写了一个这样的Dockerfile:

如果根据这个Dockerfile构建一个新image, 名字叫demo

可以看出 ping 命令在docker启动后自己执行, 但是我们可以在命令行启动docker镜像时, 执行其他命令行参数, 覆盖默认的CMD

docker启动后, 并没有执行 ping 命令, 而是运行了 hostname 命令

和CMD类似, 默认的ENTRYPOINT也在docker run时, 也可以被覆盖. 在运行时, 用--entrypoint覆盖默认的ENTRYPOINT

因为CMD命令很容易被docker run命令的方式覆盖, 所以, 如果你希望你的docker镜像的功能足够灵活, 建议在Dockerfile里调用CMD命令. 比如, 你可能有一个通用的Ruby镜像, 这个镜像启动时默认执行irb ( CMD irb ).

如果你想利用这个Ruby镜像执行任何Ruby脚本, 只需要执行这句话:

译注: ruby -e \'puts "Hello" 覆盖了 irb 命令

相反, ENTRYPOINT的作用不同, 如果你希望你的docker镜像只执行一个具体程序, 不希望用户在执行docker run的时候随意覆盖默认程序. 建议用ENTRYPOINT.

Docker在很多情况下被用来打包一个程序. 想象你有一个用python脚本实现的程序, 你需要发布这个python程序. 如果用docker打包了这个python程序, 你的最终用户就不需要安装python解释器和python的库依赖. 你可以把所有依赖工具打包进docker镜像里, 然后用

ENTRYPOINT指向你的Python脚本本身. 当然你也可以用CMD命令指向Python脚本. 但是通常用ENTRYPOINT可以表明你的docker镜像只是用来执行这个python脚本,也不希望最终用户用这个docker镜像做其他操作.

在后文会介绍如何组合使用ENTRYPOINT和CMD. 他们各自独特作用会表现得更加明显.

Dockerfile 中的 CMD 和 ENTRYPOINT 有啥区别?

【中文标题】Dockerfile 中的 CMD 和 ENTRYPOINT 有啥区别?【英文标题】:What is the difference between CMD and ENTRYPOINT in a Dockerfile?Dockerfile 中的 CMD 和 ENTRYPOINT 有什么区别? 【发布时间】:2014-02-28 11:21:48 【问题描述】:

在 Dockerfiles 中有两个与我相似的命令:CMDENTRYPOINT。但我想它们之间存在(细微的?)差异——否则,对同一件事有两个命令是没有任何意义的。

CMD 的文档说明

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

对于ENTRYPOINT

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

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

【问题讨论】:

^ 那个!谢谢@slm。这是另一个非常相似的参考资料,可能会更新一些:docs.docker.com/reference/builder/#entrypoint 和the difference between ADD and COPY一样令人困惑 此链接提供了 RUN、CMD 和 ENTRYPOINT 之间的区别:goinbigdata.com/docker-run-vs-cmd-vs-entrypoint 请注意CMDENTRYPOINT都有不同的写法,execshell形式。因此,请帮自己一个忙,并根据所使用的形式了解行为的细微差异。然后阅读docs.docker.com/engine/reference/builder/…。 我觉得这个phoenixnap.com/kb/docker-cmd-vs-entrypoint解释的很清楚。 【参考方案1】:

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

更多关于CMDENTRYPOINT之间的区别:

docker run 的参数(例如 /bin/bash)会覆盖我们在 Dockerfile 中编写的任何 CMD 命令。

ENTRYPOINT 不能在运行时被docker run [args] 等普通命令覆盖。 docker run [args] 末尾的 args 作为 ENTRYPOINT 的参数提供。这样我们就可以创建一个container,它就像一个普通的二进制文件,比如ls

所以 CMD 可以作为 ENTRYPOINT 的默认参数,然后我们可以从 [args] 覆盖 CMD args。

ENTRYPOINT 可以用--entrypoint 覆盖。

【讨论】:

【参考方案2】:

有一些很好的答案。我想通过Doc的demo来解释一下

CMD 定义容器的默认命令和/或参数。如果您需要用户可以轻松覆盖的默认命令,CMD 是最好使用的指令。 如果一个 Dockerfile 有多个 CMD,它只应用最后一个的指令。 ENTRYPOINT 在您想要定义具有特定可执行文件的容器时首选。

除非添加--entrypoint 标志,否则在启动容器时不能覆盖ENTRYPOINT

    CMD

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

【讨论】:

【参考方案3】:

我遇到了这个问题,一开始我发现说实话真的很混乱,我认为这种混乱来自使用“CMD”这个词,因为实际上那里的内容作为参数。所以在挖掘了一点之后,我明白了它是如何工作的。基本上:

ENTRYPOINT --> 您在此处指定的是容器启动时要执行的命令。如果你省略这个定义,docker 将使用/bin/sh -c bash 来运行你的容器。

CMD --> 这些是 附加到 ENTRYPOINT 的参数,除非用户指定了一些自定义参数,即:docker run ubuntu &lt;custom_cmd&gt; 在这种情况下,而不是附加指定的内容在 CMD 部分的图像上,docker 将运行ENTRYPOINT &lt;custom_cmd&gt;。如果没有指定 ENTRYPOINT,这里的内容将传递给/bin/sh -c,实际上作为启动容器时要执行的命令。

作为一切,最好通过示例来解释正在发生的事情。因此,假设我使用以下规范 Dockerfile 创建了一个简单的 docker 映像:

From ubuntu
ENTRYPOINT ["sleep"]

然后我通过运行以下命令来构建它:

docker build . -t testimg

这将创建一个容器,每次运行时它都会休眠。所以如果我按以下方式运行它:

docker run testimg

我会得到以下内容:

sleep: missing operand
Try 'sleep --help' for more information.

这是因为入口点是需要参数的“睡眠”命令。所以要解决这个问题,我只需提供睡眠量:

docker run testimg 5

这将正确运行,因此容器将运行,休眠 5 秒并退出。正如我们在这个示例中看到的,docker 只是将图像名称后面的内容附加到入口点二进制文件docker run testimg &lt;my_cmd&gt;。如果我们想将默认值(默认参数)传递给入口点会发生什么?在这种情况下,我们只需要在 CMD 部分中指定它,例如:

From ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

在这种情况下,如果用户不传递任何参数,容器将使用默认值 (10) 并将其传递给入口点 sleep。

现在让我们只使用 CMD 并省略 ENTRYPOINT 定义:

FROM ubuntu
CMD ["sleep", "5"]

如果我们重建并运行这个镜像,它基本上会休眠 5 秒。

因此,总而言之,您可以使用 ENTRYPOINT 来使您的容器充当可执行文件。您可以使用 CMD 为入口点提供默认参数,或在启动容器时运行自定义命令,用户可以从外部覆盖该命令。

【讨论】:

【参考方案4】:

根据docker docs,

CMD 和 ENTRYPOINT 指令都定义了要执行的命令 运行容器时。很少有规则可以描述他们的 合作。

    Dockerfile 应至少指定CMDENTRYPOINT 命令之一。 ENTRYPOINT 应在将容器用作可执行文件时定义。 CMD 应该用作为 ENTRYPOINT 命令定义默认参数或在 容器。 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   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"]   ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry   ║
╚════════════════════════════╩══════════════════════════════════╝

-- 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  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

【讨论】:

什么是 px_cmd 和 exec_entry ?当它们在同一条执行线上时是什么意思?它们作为参数传递给对方?即使涉及/bin/sh -c @Danielo515 'px_cmd' 和 'exec_entry' 在这里都只是虚拟字符串。您可能只是注意到/bin/sh -c 将作为前缀添加到 CMD 中,而 CMD 以可执行语法(而不是列表语法)编写。 ENTRYPOINT exec_entry p1_ent 被错误解释了。 shell 形式阻止使用任何 CMD 或运行命令行参数 - docs.docker.com/engine/reference/builder/#entrypoint @MariuszMiesiak 现在更新了。感谢您的反馈。 顺便说一句:这个答案绝对应该是公认的答案! (而the current one 声称“Docker 有一个默认入口点是/bin/sh -c”......)【参考方案5】:

• Dockerfile 应至少指定一条 CMD 或 ENTRYPOINT 指令

• 仅使用 Dockerfile 中的最后一个 CMD 和 ENTRYPOINT

• 将容器用作可执行文件时应定义 ENTRYPOINT

• 您应该使用 CMD 指令来定义默认参数 定义为 ENTRYPOINT 的命令或用于在 容器

• 使用替代参数运行容器时将覆盖 CMD

• ENTRYPOINT 设置每次访问时使用的具体默认应用程序 容器是使用图像创建的

• 如果将 ENTRYPOINT 与 CMD 结合,则可以从 CMD 中删除可执行文件 并留下将传递给 ENTRYPOINT 的参数

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

【讨论】:

【参考方案6】:

我将添加我的答案作为示例1,这可能有助于您更好地理解差异。

假设我们想要创建一个在启动时始终运行睡眠命令的图像。我们将创建自己的图像并指定一个新命令:

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

虽然这可行,但它不是一个好的解决方案,因为我们有一个多余的“睡眠”命令。为什么要冗余?因为容器的唯一目的是睡眠,所以必须显式指定sleep 命令有点尴尬。

现在让我们尝试使用ENTRYPOINT 指令:

FROM ubuntu
ENTRYPOINT sleep

此指令指定容器启动时将运行的程序

现在我们可以运行了:

docker run custom_sleep 20

默认值呢?嗯,你猜对了:

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

ENTRYPOINT 是要运行的程序,传递给容器的值会附加到它上面。

可以通过指定--entrypoint 标志覆盖ENTRYPOINT,后跟要使用的新入口点。

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

【讨论】:

这里是教程的链接:youtu.be/OYbEWUbmk90。它可能对未来的用户有用。 谢谢!这个例子的解释对我(docker初学者)来说比接受的答案要清楚得多。 我认为这个答案是最好的。对我来说,作为 Docker 中的菜鸟,这比其他答案要清楚得多。 我能在网上找到的最佳解释。非常感谢!【参考方案7】:

我已阅读所有答案,我想总结一下,以便乍一看更好地理解,如下所示:

首先,在容器中执行的整个命令包括两部分: 命令参数

ENTRYPOINT 定义了容器运行时调用的可执行文件 开始(用于命令)

CMD 指定传递给 ENTRYPOINT 的参数(用于参数)

在Kubernetes In Action 书中指出了有关它的重要说明。 (第 7 章)

虽然你可以使用 CMD 指令来指定你想要的命令 想在镜像运行的时候执行,正确的做法是做 通过 ENTRYPOINT 指令并如果您只指定 CMD 想要定义默认参数。

您也可以阅读this文章,以简单的方式获得很好的解释

【讨论】:

【参考方案8】:

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

CMD:

应使用 CMD 指令以及任何参数来运行映像中包含的软件。 CMD 应该几乎总是以CMD ["executable", "param1", "param2"…] 的形式使用。因此,如果映像用于服务,例如 Apache 和 Rails,您将运行类似 CMD ["apache2","-DFOREGROUND"] 的内容。事实上,这种形式的指令推荐用于任何基于服务的图像。

入口点:

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

【讨论】:

【参考方案9】:

Dockerfile 文件中提到的CMD 命令可以通过docker run 命令覆盖,而ENTRYPOINT 不能。

【讨论】:

docker run --help 命令另有说明:--entrypoint string Overwrite the default ENTRYPOINT of the image【参考方案10】:

这里大部分人都解释得很好,所以我不会重复所有的答案。但为了获得良好的感觉,我建议您自己通过查看容器中的进程来测试它。

创建一个很小的 ​​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"] ...

这样您就可以很容易地看到自己所有可能的方法之间的差异。

【讨论】:

【参考方案11】:

Docker 有一个默认入口点 /bin/sh -c,但没有默认命令。

当你像这样运行 docker 时: docker run -i -t ubuntu bash 入口点是默认的/bin/sh -c,图像是ubuntu,命令是bash

命令通过入口点运行。即,实际执行的是/bin/sh -c bash。这使得 Docker 能够依靠 shell 的解析器快速实现RUN

后来,人们要求能够自定义这个,所以引入了ENTRYPOINT--entrypoint

上例中ubuntu 之后的所有内容都是命令并被传递到入口点。当使用CMD 指令时,就像你在做docker run -i -t ubuntu &lt;cmd&gt; 一样。 &lt;cmd&gt; 将是入口点的参数。

如果您改为键入此命令docker run -i -t ubuntu,您也会得到相同的结果。由于 ubuntu Dockerfile 指定了默认 CMD,您仍将在容器中启动 bash shell: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

【讨论】:

一点也不。 ENTRYPOINT 设置在运行时可以(但可以被覆盖)的元数据,因此如果您不更改任何内容,启动容器后,结果将是相同的,但是,RUN 将在构建时执行,无论您做什么在运行时做,它会在这里。 默认没有ENTRYPOINT;是否使用shell取决于CMD命令(docs.docker.com/engine/reference/builder/#cmd)的使用形式。 感谢这一点,历史背景对我有很大帮助,因为我正在努力记住关于什么被覆盖和附加什么等看似晦涩难懂的规则。对于世界各地的技术文档作者来说,一个有用的观点:帮助读者建立系统的心智模型,不要只列出事实和场景:-) 这是一个绝妙的答案。我认为 Docker 文档应该在 CMD vs ENTRYPOINT 的部分下添加它。 @Webman 不,它们是两个不同的指令。如果两者都存在,则 CMD 将被视为 ENTRYPOINT 的参数。【参考方案12】:

公认的答案在解释历史方面非常出色。我发现这张表从official doc on 'how CMD and ENTRYPOINT interact' 解释得很好:

【讨论】:

【参考方案13】:

评论code中的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"]

构建: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 将是将要运行的命令。

【讨论】:

【参考方案14】:

简而言之:

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

如果您需要更多详细信息或想了解示例的不同之处,请参阅博客文章,通过大量示例全面比较 CMD 和 ENTRYPOINT - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/

【讨论】:

这是一个很棒的链接!【参考方案15】:

CMD:

CMD ["executable","param1","param2"]["executable","param1","param2"]是第一个进程。 CMD command param1 param2/bin/sh -c CMD command param1 param2 是第一个进程。 CMD command param1 param2 是从第一个进程派生出来的。 CMD ["param1","param2"]:此表单用于为ENTRYPOINT 提供默认参数。

ENTRYPOINT(以下列表不考虑 CMD 和 ENTRYPOINT 一起使用的情况):

ENTRYPOINT ["executable", "param1", "param2"]["executable", "param1", "param2"] 是第一个进程。 ENTRYPOINT command param1 param2/bin/sh -c command param1 param2 是第一个进程。 command param1 param2 是从第一个进程派生出来的。

正如creack 所说,CMD 是最先开发的。然后 ENTRYPOINT 被开发用于更多的定制。由于它们不是一起设计的,所以 CMD 和 ENTRYPOINT 之间存在一些功能重叠,这常常使人们感到困惑。

【讨论】:

【参考方案16】:

ENTRYPOINT 指定了在容器启动时始终执行的命令。

CMD 指定将提供给ENTRYPOINT 的参数。

如果你想制作一个专用于特定命令的图像,你将使用ENTRYPOINT ["/path/dedicated_command"]

否则,如果您想为通用目的制作图像,则可以不指定 ENTRYPOINT 并使用 CMD ["/path/dedicated_command"],因为您可以通过向 docker run 提供参数来覆盖该设置。

例如,如果您的 Dockerfile 是:

FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]

不带任何参数运行图像将ping localhost:

$ 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/

【讨论】:

The ENTRYPOINT specifies a command that will always be executed when the container starts. The CMD specifies arguments that will be fed to the ENTRYPOINT. 是一个很好的中肯总结。 ENTRYPOINT 也可以使用 --entrypoint 标志覆盖。例如 docker run -it --entrypoint bash test 我喜欢你的例子,真的很有帮助! @Jingguo Yao:如果CMD中包含-CMD ["nginx","-g","daemon","off"]这样的命令怎么办?会被锁链吗? ENTRYPOINT 通常指向一个条目 script(而不是命令),它可以做许多有用的事情,例如:在执行之前验证需求(例如对依赖项的就绪性探测) ;代理/包装一个命令来验证它,或者更改执行用户,或者更改文件的所有者(例如,在 Minikube 上挂载 hostPath 时,默认情况下文件会被 UID/GID @ 覆盖987654338@)等。【参考方案17】:

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

我知道ENTRYPOINT 是正在执行的二进制文件。您可以通过 --entrypoint="" 覆盖入口点。

docker run -t -i --entrypoint="/bin/bash" ubuntu

CMD 是容器的默认参数。没有入口点,默认参数是执行的命令。使用入口点, cmd 作为参数传递给入口点。您可以使用入口点模拟命令。

# 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

【讨论】:

@Blauhirn 在您的情况下,您必须以列表语法向 CMD 添加参数,并确保您指定的入口点可以解析 CMD 中的参数。通常,我会在入口点添加一个“-h”参数。然后我可以执行docker run image_name -h来显示这个图像的一些帮助信息。

以上是关于ENTRYPOINT和CMD的主要内容,如果未能解决你的问题,请参考以下文章

docker中entrypoint 和 CMD的执行总结

ENTRYPOINT和CMD

Dockerfile 和entrypoint

Dockerfile 中的 CMD 和 ENTRYPOINT 有啥区别?

Dockerfile 中 CMD 和ENTRYPOINT 的区别

Dockerfile 中的 CMD 与 ENTRYPOINT