如何在Minikube的Pod中捕获SIGTERM信号?
我之前碰到过几乎一模一样的问题!这其实和Minikube关系不大,核心坑点出在你Docker镜像的进程启动方式上,导致Kubernetes发送的SIGTERM信号没传递到你的脚本进程。
为什么收不到SIGTERM?
当你在Dockerfile里写CMD /script.sh时,Docker会默认用/bin/sh -c "/script.sh"来执行命令——这时候你的script.sh是作为sh进程的子进程在运行,而容器内的PID 1进程是sh,不是你的脚本。
Kubernetes在终止Pod时,会把SIGTERM发送给容器的PID 1进程,但sh默认不会将信号转发给它的子进程。所以你的脚本根本没机会捕获到SIGTERM,直到优雅终止时间(terminationGracePeriodSeconds)耗尽,K8s发送SIGKILL强制杀死整个容器。
而你手动进入Pod执行kill时,是直接把信号发给了脚本进程本身,所以能正常捕获,这也验证了脚本的信号处理逻辑是没问题的。
修复步骤
只需要修改Dockerfile的CMD写法,使用exec格式让你的脚本直接成为容器的PID 1进程:
FROM ubuntu COPY script.sh /script.sh RUN chmod +x /script.sh # 确保脚本有执行权限,避免潜在问题 CMD ["/script.sh"]
这种写法会让Docker直接启动/script.sh作为PID 1进程,而不是通过sh包装。此时Kubernetes发送的SIGTERM会直接被你的脚本进程收到,信号捕获逻辑就能正常工作了。
验证方法
- 重新构建镜像:
docker build -t your-image-name . - 更新Minikube里的Deployment,让它使用新镜像
- 删除一个Pod:
kubectl delete pod <pod-name> - 查看Pod的终止日志:
kubectl logs <pod-name> --previous
这时候你应该能看到日志里输出Got SIGTERM,说明脚本成功捕获到了Kubernetes发送的信号。
额外说明
如果你的Deployment配置了preStop钩子,确保它的执行逻辑不会被PID 1的问题影响(不过通常preStop是Kubelet直接触发的,和容器内进程关系不大)。但先解决PID 1的信号传递问题,是解决整个场景的核心。
内容的提问来源于stack exchange,提问作者Amir Mehler

