在面试中被问到这个问题,平时写 Dockerfile 都是从各个文件中copy的,能用就行,没有关心里面的细节,这次来弄懂一下 CMD 与 ENTRYPOINT。
一、CMD与ENTRYPOINT 的区别
资料:
cmd 官方文档 https://docs.docker.com/engine/reference/builder/#cmd
中文文档 https://dockerdocs.cn/engine/reference/builder/index.html#cmd进阶 Docker 的 ENTRYPOINT 和 CMD 参数探秘 
entrypoint 官方文档
1.1 CMD
CMD 执行三种方式:
CMD ["executable","params1","params2"]
exec 形式,常见的形式CMD ["param1","param2"]
作为 ENTRYPOINT的默认参数CMD command param1 param2
(shell form),是以/bin/sh -c
来执行的CMD echo 'test'
只能有一个CMD指令,如果有多个,只有最后一个会生效
CMD的主要目的是为执行的容器提供默认执行的命令。
默认值可以包含一个可执行文件。
如果不包含可执行文件,则必须制定一条ENTRYPOINT指令。
在EXEC这模式或者默认参数时,都是作为json来解析的,所以必须使用双引号
命令如果不以 shell 形式的话,必须使用 可执行文件的完成路径来执行
CMD ["/bin/ls","-la","/root"]
1 | FROM busybox:1.35.0 |
1.2 ENTRYPOINT
ENTRYPOINT 执行形式:
ENTRYPOINT ["executable", "param1", "param2"]
exec 形式ENTRYPOINT command param1 param2
shell 形式
这个跟CMD 类似的,不同在于以 docker run
命令行参数将追加在 exec 形式的ENTRYPOINT
,并会覆盖CMD中的所有的元素
可以使用—-entrypoint
覆盖默认的 ENTRYPOINT
docker run -i -t --rm -p 8000:80 --entrypoint ls nginx
ENTRYPOINT
shell模式阻止CMD或者run命令行参数,但是 ENTRYPOINT
指令是用 /bin/sh -c
执行的。
这样导致PID 1
的进程是 /bin/sh
而不是ENTRYPOINT
可执行程序,这样导致收不到Unix signals(只有PID 1的进程可以收到)
也就收不到来自 docker stop <container>
的SIGTERM
,可以使用exec 模式解决这个问题
1 |
|
官方文档提示的捕获TERM信号,来 gracefully shutdown
1 |
|
二、疑问
2.1 CMD 与 ENTRYPOINT 什么时候使用
通过示例展示如何使用
1 |
|
1 | FROM ubuntu:latest |
1 | docker build . -t cmd:test |
官方有个表格,展示了CMD
与 ENTRYPOINT
执行时的情况
No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT [“exec_entry”, “p1_entry”] | |
---|---|---|---|
No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”, “p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
简单总结就是: 
使用
ENTRYPOINT
shell形式的,就不会管CMD
,一般不用 shell模式,进程PID不为1,被/bin/sh
占用了使用
ENTRYPOINT
exec 形式的,会结合CMD
总是使用 ENTRYPOINT
总没错的
2.2 CMD中如何获取ENV
使用
CMD echo ${mode}
shell 形式使用
CMD ["/bin/sh","-c","echo ${mode}"]
使用CMD ["echo","${HOME}" ]
是获取不到HOME的,因为使用exec模式,不是使用sh
来执行命令的