CSDN 中文章不一定能及时更新,欢迎点击前往我的博客查看最新版本:许盛的博客
Dockerfile
中的 CMD
命令,有 exec form
和 shell form
两种形式,具体区别可以参考: Dockerfile 中 CMD 写法的区别
推荐使用 exec form
而不是 shell form
,因为使用 exec form
时可以将实际的应用程序作为容器中的主进程,而使用 shell form
时,容器中的主进程实际上是 sh
。
当我们需要终止一个容器时,需要向这个容器传递 signal
,然后由主进程捕获 signal
并退出。
但是 sh
默认并不会处理 signal(kill 除外)
,在 k8s
集群中终止容器时,会先向其发送 SIGTERM
信号,然后由应用程序响应后自行退出,达到优雅退出的目的。
如果容器的主进程是 sh
,那么 sh
接收到信息后,并不会传递给子进程,也不会退出,会导致容器退出失败,等待超时后被 k8s
强制 kill
掉。
可以实践一下进行验证。
exec form 写法
准备一个 Dockerfile 文件,内容如下:
FROM nginx
MAINTAINER https://www.xuxusheng.com
CMD ["nginx", "-g", "daemon off;"]
这种写法就是 exec form
,基于此镜像运行的容器内主进程应该为 nginx
。
再使用如下命令运行一个容器起来。
# 构建镜像
docker build -t my-nginx .
# 运行容器
docker run --name my-nginx my-nginx
可以看到容器正常启动了。
再通过命令 docker top my-nginx
可以看到:
此时容器中主进程为 nginx
。
再使用 ps
命令查询到刚才运行的 docker run
命令的 pid
:
如上所示,使用命令 kill -15 <pid>
向其传递 SIGTERM
信号,会发现容器正常退出。
直接在容器运行的终端中使用 ctrl + c
也会正常退出(传递 SIGINT
信号)。
shell form
准备如下 Dockerfile
文件:
FROM nginx
MAINTAINER https://www.xuxusheng.com
CMD nginx -g "daemon off;"
这种写法为 shell form
形式,容器中主进程会变成 sh
。
重复上一节中的各个步骤,可以看到 docker top
命令输出如下:
此时不管是使用 kill -15 <pid>
还是 ctrl + c
方式,会发现容器都无法正常退出。
所以结论是,尽量避免使用 CMD
的 shell form
写法,让容器中的主进程是你的应用程序而不是 sh
,避免容器无法正常退出。