You need to enable JavaScript to run this app. Docker环境下Bash脚本无法捕获SIGINT/SIGTERM信号问题咨询
优惠活动
大模型
产品
解决方案
定价
更多

Docker环境下Bash脚本无法捕获SIGINT/SIGTERM信号问题咨询

Docker 容器内Bash脚本无法捕获SIGINT/SIGTERM的原因
  • 信号未转发:默认执行docker run时不会分配交互终端,也不会将宿主机的stdin和信号转发到容器内,你本地按下Ctrl+C产生的SIGINT信号根本没有传递到容器内部的脚本进程,自然不会触发trap逻辑。
  • Bash信号处理机制限制:Bash在等待前台子进程运行时会阻塞所有信号处理。你的脚本最后执行的sleep 100000是前台子进程,Bash会一直阻塞到sleep运行结束才会处理收到的SIGINT、SIGTERM信号;而sleep 100000的运行时长远超过docker stop默认的10秒超时时间,超时后Docker会直接发送SIGKILL强制销毁容器,所以你看不到信号触发的日志输出。
  • PID1进程特殊规则:Linux系统中PID为1的进程有特殊的信号处理逻辑,默认会忽略所有没有显式注册处理函数的信号,你这里虽然已经注册了信号trap,但配合上Bash的前台进程等待阻塞逻辑,进一步导致信号无法被及时处理。
  • 补充验证:你当前Dockerfile使用的CMD ["/app/start.sh"]是exec格式,会直接将bash脚本作为容器PID1运行,逻辑是正确的;如果使用shell格式CMD /app/start.sh,容器PID1会是/bin/sh -c进程,信号会被该进程拦截,根本无法传递到你的bash脚本。
解决方案
  1. 调整Bash脚本逻辑,将长时间运行的进程放到后台执行,通过wait命令等待,此时Bash可以在等待期间正常响应信号:
#!/bin/bash
trap "echo SIGINT; kill ${sleep_pid}; exit" SIGINT
trap "echo SIGTERM; kill ${sleep_pid}; exit" SIGTERM
echo Starting script
# 将sleep放到后台运行
sleep 100000 &
# 记录后台sleep进程的PID
sleep_pid=$!
# 等待sleep进程结束,等待期间Bash可正常处理信号
wait ${sleep_pid}
  1. 如果需要前台运行容器时Ctrl+C能正常生效,启动容器时添加-it参数开启交互终端和信号转发:
docker run -it --name tmp tmp
  1. 也可以在启动容器时添加--init参数,让Docker内置的轻量init进程作为容器PID1,它会自动转发所有信号给子进程,同时适配PID1的特殊信号处理规则,避免原生Bash作为PID1的信号处理异常:
docker run --init --name tmp tmp

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 11:57:03