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

Docker容器内多进程无法接收SIGTERM信号问题排查求助

问题原因与解决方案

核心原因:信号无法传递到Go进程

当K8s销毁容器时,会向容器的PID 1进程发送SIGTERM信号,但你的场景中PID 1是run.sh对应的shell进程,存在两个关键问题:

  1. Bash作为PID 1时,默认忽略SIGTERM信号(Unix系统对PID 1的特殊规则),不会主动将信号转发给后台子进程。
  2. run.sh中用&启动Go进程作为后台任务,随后用wait等待,但shell没有配置信号转发逻辑,导致SIGTERM无法传递到Go进程,自然看不到信号处理日志。

具体解决方案

方案1:让Go进程直接成为PID 1(推荐单实例场景)

修改K8s Deployment的启动命令,跳过shell脚本,直接启动Go二进制文件,让它成为PID 1,这样就能直接接收SIGTERM信号:

- name: ztest
  image: xxx/test
  imagePullPolicy: IfNotPresent
  args:
  - ./ztest
  - --config-location
  - plugins_hello/your-config-dir/
  - --config-name
  - your-config-name

如果需要启动多个Go实例,建议将遍历配置目录的逻辑迁移到Go代码内部,用goroutine或进程管理方式实现,避免依赖shell。

方案2:修改shell脚本,添加信号转发逻辑(多实例场景)

在run.sh中添加信号捕获与转发逻辑,当shell收到SIGTERM时,主动将信号发送给所有后台Go进程:

# 定义信号处理函数,转发SIGTERM给所有子进程
handle_sigterm() {
    echo "Shell received SIGTERM, forwarding to child processes..."
    kill -TERM "${child_pids[@]}"
    wait
}

# 捕获SIGTERM信号,触发处理函数
trap 'handle_sigterm' SIGTERM

# 存储子进程PID的数组
child_pids=()

for d in plugins_"$repo_name"/*/;
do
  ./ztest --config-location "$dir"/ --config-name $(basename "$filename") &
  # 记录每个Go进程的PID
  child_pids+=($!)
done;

wait

这样shell收到SIGTERM后,会将信号传递给所有后台Go进程,你的Go代码就能正常捕获并输出日志。

额外检查点

  • 确认K8s的terminationGracePeriodSeconds配置(默认30秒)足够长,确保Go进程有时间完成优雅退出逻辑。
  • 验证Go代码的信号监听逻辑:你的代码中signal.Notify已经正确注册SIGTERM,只要信号能传递到进程,就能触发日志输出。

内容的提问来源于stack exchange,提问作者BAE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:52:49