You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:59:50