问:
在 Dockerfiles 中有两个和我类似的命令:CMD 和 ENTRYPOINT。但我猜想它们之间存在(细微的?)差异——否则对于同一件事有两个命令是没有任何意义的。
CMD 的文档说明
CMD 的主要目的是为执行容器提供默认值。
对于 ENTRYPOINT:
ENTRYPOINT 可帮助您配置可以作为可执行文件运行的容器。
那么,这两个命令有什么区别呢?
答1:
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
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 入口点的参数是 。
如果您改为键入此命令 docker run -i -t ubuntu,您也会得到相同的结果:bash shell 将在容器中启动,因为在 ubuntu Dockerfile 中指定了默认的 CMD: 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 的参数。
答2:
huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!
ENTRYPOINT 指定在容器启动时始终执行的命令。
CMD 指定将提供给 ENTRYPOINT 的参数。
如果您想制作专用于特定命令的图像,您将使用 ENTRYPOINT [“/path/dedicated_command”]
否则,如果您想为通用目的制作图像,您可以不指定 ENTRYPOINT 并使用 CMD [“/path/dedicated_command”],因为您可以通过向 docker run 提供参数来覆盖该设置。
例如,如果您的 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/
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 覆盖{ 3})等。
答3:
打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!
根据docker docs,
CMD 和 ENTRYPOINT 指令都定义了运行容器时执行的命令。很少有规则描述他们的合作。 Dockerfile 应至少指定 CMD 或 ENTRYPOINT 命令之一。将容器用作可执行文件时应定义 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”......)
答4:
huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式
是的,这是个好问题。我还没有完全理解,但是:
我了解 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 来显示该图像的一些帮助信息。
答5:
与HuntsBot一起,探索全球自由职业机会–huntsbot.com
简而言之:
CMD 设置默认命令和/或参数,可以在 docker 容器运行时从命令行覆盖。
ENTRYPOINT 命令和参数不会被命令行覆盖。相反,所有命令行参数都将添加到 ENTRYPOINT 参数之后。
如果您需要更多详细信息或想了解示例的不同之处,可以使用博客文章全面比较 CMD 和 ENTRYPOINT 以及大量示例 - https://codewithyury.com/docker-run-vs-cmd-vs-entrypoint/
这是一个很棒的链接!
答6:
huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求
直觉上 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 run [args] 末尾的 args 作为 ENTRYPOINT 的参数提供。通过这种方式,我们可以创建一个 container,它就像一个普通的二进制文件,例如 ls。
所以 CMD 可以作为 ENTRYPOINT 的默认参数,然后我们可以从 [args] 覆盖 CMD args。
ENTRYPOINT 可以用 --entrypoint 覆盖。
答7:
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
我将添加我的答案作为示例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 中的菜鸟,这比其他答案要清楚得多。
我能在网上找到的最佳解释。非常感谢!
答8:
huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式
有一些很好的答案。我想通过 Doc 的演示来解释它
CMD 定义容器的默认命令和/或参数。如果您需要用户可以轻松覆盖的默认命令,CMD 是最好使用的指令。如果一个 Dockerfile 有多个 CMD,它只应用最后一个的指令。
当您要定义具有特定可执行文件的容器时,首选 ENTRYPOINT。
除非您添加 --entrypoint 标志,否则您在启动容器时不能 覆盖ENTRYPOINT 。
命令
码头工人文件
FROM centos:8.1.1911
CMD ["echo", "Hello Docker"]
运行结果
$ sudo docker run
Hello Docker
$ sudo docker run hostname # hostname is exec to override CMD
244be5006f32
入口点
码头工人文件
FROM centos:8.1.1911
ENTRYPOINT ["echo", "Hello Docker"]
运行结果
$ sudo docker run
Hello Docker
$ sudo docker run hostname # hostname as parameter to exec
Hello Docker hostname
在很多情况下,将 CMD 和 ENTRYPOINT 结合起来是 Docker 容器的最佳解决方案。在这种情况下,可执行文件使用 ENTRYPOINT 定义,而 CMD 指定默认参数。
码头工人文件
FROM centos:8.1.1911
ENTRYPOINT ["echo", "Hello"]
CMD ["Docker"]
运行结果
$ sudo docker run
Hello Docker
$ sudo docker run Ben
Hello Ben
答9:
HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com
https://i.stack.imgur.com/gVtK9.jpg
答10:
打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!
我遇到了这个问题,一开始我发现说实话真的很混乱,我认为这种混乱来自使用“CMD”这个词,因为实际上那里的内容充当了论点。所以在挖掘了一点之后,我明白了它是如何工作的。基本上:
入口点 -->您在此处指定的是容器启动时要执行的命令。如果您省略此定义,docker 将使用 /bin/sh -c bash 来运行您的容器。
CMD -->这些是 附加到 ENTRYPOINT 的参数,除非用户指定了一些自定义参数,即:docker run ubuntu <custom_cmd> 在这种情况下,而不是附加在 CMD 部分中图像上指定的内容,docker 将运行 ENTRYPOINT <custom_cmd> .如果没有指定 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 <my_cmd>。如果我们想将默认值(默认参数)传递给入口点会发生什么?在这种情况下,我们只需要在 CMD 部分中指定它,例如:
From ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]
在这种情况下,如果用户不传递任何参数,容器将使用默认值 (10) 并将其传递给入口点 sleep。
现在让我们只使用 CMD 并省略 ENTRYPOINT 定义:
FROM ubuntu
CMD ["sleep", "5"]
如果我们重建并运行这个镜像,它基本上会休眠 5 秒。
因此,总而言之,您可以使用 ENTRYPOINT 使您的容器充当可执行文件。您可以使用 CMD 为入口点提供默认参数,或者在启动容器时运行自定义命令,用户可以从外部覆盖该命令。
答11:
huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。
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
ps:在存在EntryPoint 的情况下,CMD 将保存参数以馈送到EntryPoint。在没有 EntryPoint 的情况下,CMD 将是将要运行的命令。
保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com
与HuntsBot一起,探索全球自由职业机会–huntsbot.com