Docker容器内shell脚本trap <action> SIGTERM捕获不生效问题
问题原因
你的脚本存在2个核心错误,直接导致SIGTERM信号无法被正常处理:
_term信号处理函数存在语法错误:函数内写的stop()是重新定义一个名为stop的空函数,并非调用你提前写好的服务停止逻辑,就算信号被捕获,也不会执行任何清理操作。- 阻塞命令
sleep infinity会卡住shell的信号处理流程:多数发行版默认的sh(比如dash)在等待前台外部命令执行时,不会立刻触发注册的trap逻辑,必须等前台命令执行完毕才会处理信号,而sleep infinity永远不会主动退出,直接导致信号捕获逻辑完全无法触发。
修复步骤
- 修正信号处理函数的语法错误,补充主动退出逻辑,修改后代码如下:
_term() { echo "Caught SIGTERM signal!" stop exit 0 } - 替换会阻塞信号的
sleep infinity长驻逻辑,使用shell内置的wait命令阻塞,内置命令不会中断trap的信号响应:
如果基础环境不支持wait的长驻逻辑,也可以替换为短周期sleep循环,定期给shell让出信号处理的时机:if ! tty --silent then wait fiif ! tty --silent then while true; do sleep 1; done fi - (推荐优化)将ENTRYPOINT使用的shell从
sh替换为bash,信号处理兼容性更稳定,对应Dockerfile配置修改为:# 记得提前在镜像构建步骤安装bash,比如Debian/Ubuntu镜像执行apt install -y bash ENTRYPOINT ["bash","/home/run.sh"] CMD ["start"] - (可选优化)在stop函数末尾补充子进程清理逻辑,避免后台残留进程导致容器无法正常退出:
stop() { echo 'Server stopping' pkill mapmon.sh sudo /etc/init.d/postgresql stop sudo /etc/init.d/apache2 stop sudo /etc/init.d/renderd stop # 清理当前shell启动的所有后台进程 kill -TERM $(jobs -p) 2>/dev/null }
完成以上修改后,执行docker stop时容器就会正常打印信号捕获和服务停止的日志,完成清理后主动退出,不会等10秒超时被Docker强制杀死。
内容的提问来源于stack exchange,提问作者Saurabh Batra
相关产品推荐
相关产品推荐

