详解如何在 docker 容器中捕获信号

2020-06-17 06:35:05易采站长站整理

在脚本中捕获信号

创建另外一个启动应用程序的脚本文件 app2.sh,内容如下:


#!/usr/bin/env bash
set -x

pid=0

# SIGUSR1-handler
my_handler() {
echo "my_handler"
}

# SIGTERM-handler
term_handler() {
if [ $pid -ne 0 ]; then
kill -SIGTERM "$pid"
wait "$pid"
fi
exit 143; # 128 + 15 -- SIGTERM
}
# setup handlers
# on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handler
trap 'kill ${!}; my_handler' SIGUSR1
trap 'kill ${!}; term_handler' SIGTERM

# run application
node app &
pid="$!"

# wait forever
while true
do
tail -f /dev/null & wait ${!}
done

这个脚本文件在启动应用程序的同时可以捕获发送给它的 SIGTERM 和 SIGUSR1 信号,并为它们添加了处理程序。其中 SIGTERM 信号的处理程序就是向我们的 node 应用程序发送 SIGTERM 信号。

然后创建 Dockerfile2 文件,内容如下:


FROM iojs:onbuild
COPY ./app.js ./app.js
COPY ./app2.sh ./app2.sh
COPY ./package.json ./package.json
RUN chmod +x ./app2.sh
EXPOSE 3000
ENTRYPOINT ["./app2.sh"]

接下来创建镜像:


$ docker build --no-cache -t signal-app2 -f Dockerfile2 .

然后启动容器运行应用程序:


$ docker run -it --rm -p 3000:3000 --name="my-app2" signal-app2

此时 node 应用在容器中的进程号也不是 1,但是它却可以接收到 SIGTERM 信号并优雅的退出了:

结论

容器中的 1 号进程是非常重要的,如果它不能正确的处理相关的信号,那么应用程序退出的方式几乎总是被强制杀死而不是优雅的退出。究竟谁是 1 号进程则主要由 EntryPoint, CMD, RUN 等指令的写法决定,所以这些指令的使用是很有讲究的。

您可能感兴趣的文章:docker容器如何优雅的终止详解Docker 容器操作退出后进入解决办法Docker常用的清除容器镜像命令小结Docker 解决容器时间与主机时间不一致的问题三种解决方案Docker为网络bridge模式指定容器ip的方法如何在Docker容器内外互相拷贝数据Docker容器中文乱码(修改docker容器编码格式)的解决方案Docker 容器内存监控原理及应用详解挂载运行的docker容器中如何挂载文件系统两种方式创建docker镜像的启动容器时区别介绍(总结篇)