如何判断Docker容器执行stop后进程是否为优雅终止
判定docker stop终止类型的可行方法
docker stop 默认执行逻辑是先向容器主进程发送SIGTERM信号,若进程在设定的超时周期(默认10秒,可通过-t/--time参数自定义)内未终止,就发送SIGKILL信号强制杀死进程。该命令执行完成后无论终止类型是什么,返回值始终为0,无法直接通过返回值判定结果,可通过以下两种方案实现准确判断:
方案1:结合停止耗时+容器退出码判断(简便首选)
- 判定逻辑:
- 进程被SIGKILL信号强制杀死时,退出码固定为137(计算规则:128 + SIGKILL对应的信号值9);如果进程收到SIGTERM后优雅退出,退出码为进程自身返回值(正常退出一般为0)
- 若整个停止操作的耗时大于等于你设置的stop超时时间,同时退出码为137,即可确认是超时后被强制杀死
- 操作示例:
# 定义停止超时时间,和后续docker stop的-t参数值保持一致即可,默认10秒就填10 STOP_TIMEOUT=10 # 记录停止操作启动时间 START_TS=$(date +%s) # 执行容器停止 docker stop -t ${STOP_TIMEOUT} test_container # 记录停止完成时间 END_TS=$(date +%s) # 拉取容器退出码 EXIT_CODE=$(docker inspect test_container --format='{{.State.ExitCode}}') # 结果判定 COST_TIME=$((END_TS - START_TS)) if [ $EXIT_CODE -eq 137 ] && [ $COST_TIME -ge $STOP_TIMEOUT ]; then echo "判定结果:容器超时后被SIGKILL强制终止" else echo "判定结果:容器收到SIGTERM后优雅终止,进程退出码为$EXIT_CODE" fi
方案2:通过Docker事件流精准判定(无误差)
- 判定逻辑:Docker daemon会完整记录容器生命周期的所有事件,包括触发容器退出的具体信号值,直接读取事件里的信号字段即可100%确认终止原因,不会和其他场景的进程退出混淆
- 操作示例:
# 创建临时文件存储事件记录 TMP_EVENT=$(mktemp) # 后台启动事件监控,只捕获目标容器的退出事件,提取触发退出的信号值 docker events --filter 'container=test_container' --filter 'event=die' --format '{{.Actor.Attributes.signal}}' > $TMP_EVENT & MONITOR_PID=$! # 等待监控进程就绪 sleep 1 # 执行停止操作 docker stop test_container # 等待事件写入完成后关闭监控进程 sleep 1 kill $MONITOR_PID # 读取信号值 EXIT_SIGNAL=$(cat $TMP_EVENT) rm -f $TMP_EVENT # 结果判定 if [ "$EXIT_SIGNAL" = "9" ]; then echo "判定结果:容器被SIGKILL(信号值9)强制杀死,属于超时强杀" elif [ "$EXIT_SIGNAL" = "15" ]; then echo "判定结果:容器收到SIGTERM(信号值15)后优雅退出" else echo "判定结果:容器被其他信号终止,信号值为$EXIT_SIGNAL" fi
补充注意事项
如果容器主进程没有正确注册SIGTERM信号处理逻辑(比如shell脚本作为1号进程时未用exec启动业务进程,导致SIGTERM被shell忽略),无论执行多少次docker stop都会触发超时强杀,这种场景建议先调整容器入口启动逻辑,保证信号能正确传递给业务进程。
内容的提问来源于stack exchange,提问作者hermit.crab
相关产品推荐
相关产品推荐

