FastAPI Docker容器忽略SIGTERM:Pod终止慢且生命周期关闭钩子未执行
问题原因与解决方案
问题根源
你的容器中PID 1进程是/bin/sh -c ...,而非FastAPI的Python进程:
- Docker默认会为
CMD的shell模式(不带方括号的形式)启动一个sh进程作为PID 1 - Linux系统中,PID 1进程不会自动将信号(如
SIGTERM)转发给子进程 - 当执行
docker stop或k8s删除Pod时,SIGTERM只会发给PID 1的sh进程,而sh不会把信号传给Python进程 - 等待宽限期耗尽后,系统会发送
SIGKILL强制终止所有进程,导致FastAPI的lifespan关闭钩子完全没机会执行,容器销毁耗时久
解决方法
只需让FastAPI的Python进程成为容器的PID 1进程,就能直接接收SIGTERM信号并触发优雅关闭逻辑,有两种实现方式:
方式1:使用exec形式的CMD
修改Dockerfile的CMD为数组形式(exec模式),让Python进程直接作为PID 1启动:
CMD ["fastapi", "run", "app/main.py", "--port", "8080"]
方式2:用exec命令替换shell进程
如果需要保留shell模式的前置逻辑,可通过exec命令让FastAPI进程取代当前的sh进程,成为PID 1:
CMD exec fastapi run app/main.py --port 8080
验证方法
- 重新构建镜像:
docker build -t myapp:dev .
- 启动容器并测试关闭:
docker run --name myapp myapp:dev # 另一个终端执行 time docker stop myapp
此时docker stop应该会在几秒内完成,同时FastAPI的lifespan关闭钩子会正常执行(可在钩子中添加日志输出验证)。
在k3d集群中部署修改后的镜像后,执行kubectl delete pod或滚动更新时,Pod会快速销毁,不会再等待30秒宽限期。
内容的提问来源于stack exchange,提问作者user3647374
相关产品推荐
相关产品推荐

