Kubernetes删除Pod时未发送SIGTERM信号问题排查
问题根因
问题出在Dockerfile的CMD指令写法上,和Kubernetes配置、权限配置均无关。
你当前使用的是shell格式的启动命令CMD ${CMD},Docker执行这类格式的命令时,会自动通过/bin/sh -c包裹启动目标程序,最终容器内PID为1的进程是shell,而非你实际运行业务服务的进程。
Linux系统中PID 1进程有特殊的信号处理规则:默认情况下shell进程不会将收到的SIGTERM信号转发给它拉起的子进程,这就导致Kubernetes发送的终止信号被PID 1的shell拦截,根本没有传递到业务进程,直到默认30秒宽限期结束后发送SIGKILL强制销毁整个容器。
你手动通过kubectl exec进入Pod执行kill -15能正常触发优雅关停逻辑,是因为该操作直接将信号发送给了业务进程本身,绕过了PID 1的shell层,和Kubernetes发信号的链路不一样。
修复方案
核心思路是让你的业务服务进程直接成为容器内的PID 1进程,直接接收Kubernetes传递的信号,有两种可行写法:
- 使用exec格式的CMD指令(推荐)
exec格式是JSON数组形式,Docker不会额外调用shell包裹启动,会直接运行业务进程成为PID 1。注意该格式不支持shell变量展开,你可以直接写入确定的服务启动路径:# 替换原有的ENV和CMD配置 CMD ["./你的服务二进制文件名"] - 保留变量传参的写法,加
exec前缀
如果你需要保留通过ARG SERVICE传入服务名的逻辑,可以在启动命令前加exec,让shell启动业务进程后主动退出,由业务进程接管PID 1:ENV CMD=./${SERVICE} CMD exec ${CMD}
验证方法
修改配置重新构建镜像启动Pod后,可以通过以下方式确认修复生效:
- 进入容器执行
ps aux,查看PID为1的进程是否为你的业务服务进程,而非/bin/sh - 触发Pod删除/滚动更新操作,观察业务进程是否能在30秒宽限期内收到
SIGTERM执行优雅退出逻辑,不需要等满30秒被强制杀死
内容的提问来源于stack exchange,提问作者abcalphabet
相关产品推荐
相关产品推荐

