在Dockerfiles中,有两个命令看起来很相似:CMD
和ENTRYPOINT
。但我猜它们之间有一个(微妙的)区别--否则就没有任何意义,有两个命令来处理同样的事情。
`CMD'的文档指出
CMD的主要目的是为执行中的容器提供默认值。
以及 "ENTRYPOINT"。
一个ENTRYPOINT可以帮助你配置一个你可以作为可执行文件运行的容器。
那么,这两个命令之间有什么区别?
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 "指定了一个在容器启动时将一直被执行的命令。
CMD'指定了将被送入
ENTRYPOINT'的参数。
如果你想让一个图像专门用于一个特定的命令,你将使用ENTRYPOINT ["/path/dedicated_command"]
。
否则,如果你想制作一个通用的镜像,你可以不指定ENTRYPOINT
,而使用CMD ["/path/dedicated_command"]
,因为你将能够通过向docker run
提供参数来覆盖这个设置。
例如,如果你的Docker文件是。
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/
根据[docker docs](https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact)。
&gt.CMD和ENTRYPOINT指令都定义了执行什么命令。 CMD和ENTRYPOINT指令都定义了执行的命令。
当运行容器时。 几乎没有什么规则来描述它们 合作。 合作。
Dockerfile应该指定至少一个
CMD
或ENTRYPOINT
命令。2;
当使用容器作为可执行文件时,应该定义
ENTRYPOINT
。 3;
CMD
应该被用来定义ENTRYPOINT
命令的默认参数,或者用来在容器中执行临时命令。 容器。当用其他参数运行容器时,
CMD
将被覆盖。
下面的表格显示了不同的ENTRYPOINT
/CMD
组合会执行什么命令。
-- 无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 ║
╚════════════════════════════╩═════════════════════════════════════════════════╝
是的,这是个好问题。我还没有完全理解它,但是。
我理解ENTRYPOINT
是正在执行的二进制文件。你可以通过 --entrypoint=""来覆盖entrypoint。
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMD是容器的默认参数。在没有入口点的情况下,默认参数是被执行的命令。有入口时,cmd作为参数被传递给入口。你可以用entrypoint模拟一个命令。
# 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"]
和
docker build -t=cat .
那么你可以使用。
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default 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参数。
ENTRYPOINT可以用--entrypoint
覆盖。
公认的答案在解释历史上是美妙的。 我发现这个表格很好地解释了它从[官方文档上的'如何CMD和ENTRYPOINT互动'][1]。 [![在此输入图片描述][2]][2]。
[1]: https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact [2]: https://i.stack.imgur.com/gVtK9.jpg
我把我的回答加进去作为例子1 这可能会帮助你更好地理解其中的区别。
让我们'假设我们想创建一个映像,当它启动时将总是运行睡眠命令。 我们将创建我们自己的映像并指定一个新的命令。
FROM ubuntu
CMD睡眠10
```
现在,我们建立形象。
```
docker build -t custom_sleep .
docker run custom_sleep
# sleeps for 10 seconds and exits
```
如果我们想改变秒数呢?
我们必须改变`Dockerfile`,因为它的值是硬编码的,或者通过提供一个不同的命令来覆盖这个命令。
```
docker run custom_sleep sleep 20
```
虽然这个方法可行,但它并不是一个好的解决方案,因为我们有一个多余的"sleep".命令(容器&39;的目的是*sleep*,所以必须明确指定`sleep`命令不是一个好的做法)。
命令(容器'的目的是*睡眠,所以必须明确指定`sleep`命令不是一个好的做法)。
现在让我们尝试使用`ENTRYPOINT`指令。
```bash
FROM ubuntu
ENTRYPOINT 睡眠
```
这条指令*指定了容器启动时要运行的程序*。
现在我们可以运行了。
````bash
docker run custom_sleep 20
```
那默认值呢?
嗯,你猜对了。
```bash
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]
```
`ENTRYPOINT`是将要运行的程序,传递给容器的值将被追加到它上面。
可以通过指定一个`--entrypoint`标志来覆盖`ENTRYPOINT`,后面再加上你要使用的新的入口点。
<sup>不是我的,我曾经看过一个教程,提供了这个例子</sup>。
关于[code][1]中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"]
构建.Sudo docker build -t ent_cmd : 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
p.s: 在有EntryPoint的情况下,CMD将持有参数,并提供给EntryPoint。 在没有EntryPoint的情况下,CMD将是将要运行的命令。
CMD:
CMD ["executable","param1","param2"]
。
["executable","param1","param2"]
是第一个进程。CMD命令param1 param2
。
/bin/sh -c CMD command param1 param2
是第一个进程。
CMD命令param1 param2
是从第一个进程分叉出来的。CMD ["param1","param2"]
。
此表单用于为ENTRYPOINT
提供默认参数。ENTRYPOINT (以下列表不考虑CMD和ENTRYPOINT一起使用的情况)。
ENTRYPOINT ["executable", "param1", "param2"]
:
["executable","param1","param2"]
是第一个进程。ENTRYPOINT命令param1 param2
。
/bin/sh -c command param1 param2
是第一个进程。
command param1 param2
是从第一个进程分叉出来的。正如creack所说,CMD是先开发出来的。 然后又开发了ENTRYPOINT,以满足更多用户的需求。 由于它们不是设计在一起的,所以CMD和ENTRYPOINT之间有一些功能上的重叠,常常让人感到困惑。
大多数人在这里解释得很完美,所以我不会重复所有的答案。 但为了获得良好的感觉,我建议你自己通过查看容器中的进程来进行测试。
创建一个微小的Docker文件,形式如下。
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"]
。这样你就可以很容易地看到所有可能的方法之间的差异,为自己。