Docker中entrypoint启动的子进程无法接收SIGTERM信号问题排查
Docker容器中entrypoint脚本子进程无法接收SIGTERM实现优雅退出的问题
我运行一个entrypoint脚本,它会启动多个子服务进程,希望docker stop或docker restart能将SIGTERM信号传递给这些子进程,但始终无法实现。
当前配置
Dockerfile的ENTRYPOINT设置
采用exec模式启动entrypoint脚本:
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
现有的entrypoint.sh脚本
脚本里启动各服务时都用了exec,理论上应该保留父子进程PID关系,当前脚本内容如下:
#!/bin/bash child_pids=() apache2() { source /etc/apache2/envvars source /etc/default/apache-htcacheclean exec /usr/sbin/apache2 -D NO_DETACH } naemon() { exec sudo -u naemon /usr/bin/naemon /etc/naemon/naemon.cfg } pdagent() { exec sudo -u pdagent /usr/share/pdagent/bin/pdagentd.py } postfix() { if! [ "${MAIL_RELAY_HOST}" = "" ]; then sed -i "s/relayhost =.*/relayhost = ${MAIL_RELAY_HOST}/" /etc/postfix/main.cf fi if! [ "${MAIL_INET_PROTOCOLS}" = "" ]; then sed -i "s/inet_protocols =.*/inet_protocols = ${MAIL_INET_PROTOCOLS}/" /etc/postfix/main.cf fi sed -i "s/myhostname =.*/myhostname = $(hostname)/" /etc/postfix/main.cf sed -i "s/mydestination =.*/mydestination = ${NAEMON_FQDN}, \$myhostname, localhost.localdomain, localhost/" /etc/postfix/main.cf sed -i "/^myorigin =.*/d" /etc/postfix/main.cf echo "${NAEMON_FQDN}" > /etc/mailname # postfix运行在chroot环境,需要resolv.conf解析主机名 cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf exec /usr/lib/postfix/sbin/master -d -c /etc/postfix } xinetd() { exec /usr/sbin/xinetd -dontfork -pidfile /run/xinetd.pid } terminate_children() { echo "Terminating child processes..." for pid in "${child_pids[@]}"; do kill -SIGTERM "$pid" 2>/dev/null echo "Sent SIGTERM to PID $pid" wait "$pid" done } naemon & child_pids+=("$!") apache2 & child_pids+=("$!") pdagent & child_pids+=("$!") postfix & child_pids+=("$!") xinetd & child_pids+=("$!") echo ${child_pids[@]} trap terminate_children SIGINT SIGTERM wait
遇到的问题
脚本的逻辑是将每个子进程后台启动,把PID存入数组,捕获SIGTERM信号后调用terminate_children()函数,通过kill向对应PID发送SIGTERM并等待子进程退出。但实际执行时出现以下问题:
- 执行
docker restart或docker stop时,日志显示已向Naemon的PID发送SIGTERM,但Docker仍会等待10秒超时后强制终止所有进程 - 使用
docker stop --time -1禁用超时后,命令会无限等待,子进程无法退出 - 手动进入容器的bash执行
kill -SIGTERM <pid>时,子进程可以正常优雅退出
尝试过的其他方案
我还尝试用tini作为entrypoint来启动我的entrypoint脚本(已禁用脚本自身的trap语句),但执行docker stop或docker restart时,tini似乎完全不响应SIGTERM,直接强制终止所有关联进程。
请问我哪里操作有误?如何让子进程实现优雅退出?
内容的提问来源于stack exchange,提问作者eroji
相关产品推荐
相关产品推荐

