stopsignal仅指定docker stop时发送给pid 1进程的信号,不触发多级信号或执行脚本;需与应用信号处理、启动方式及stop-grace-period协同才能实现优雅退出。

STOPSIGNAL 本身不定义“信号链路”,它只指定 docker stop 命令最终向 PID 1 进程发送哪个信号。所谓“定制信号链路”,本质是把 STOPSIGNAL、应用信号处理逻辑、容器启动方式和外部协调机制四者对齐——缺一不可。
明确 STOPSIGNAL 的定位:只改“第一枪”的型号
STOPSIGNAL 不触发多级信号,也不执行脚本或命令。它只是告诉 Docker:“当我运行 docker stop 时,请把以下信号发给容器主进程”:
- 默认是 SIGTERM(数值 15),这也是最通用、最推荐的选择;
- 可显式设为 SIGINT(如交互式 CLI 工具)、SIGUSR1(如自定义热重载/冻结逻辑)等;
- 不能设为 SIGKILL(9)或 SIGSTOP(19),因为这两个信号无法被应用捕获,违背“优雅退出”初衷。
让有状态应用真正响应这个信号
光改 STOPSIGNAL 没用,关键在应用自身是否监听并执行清理流程。以典型有状态服务为例:
- 数据库类(PostgreSQL/Redis):原生支持 SIGTERM,会完成 WAL 刷盘、关闭监听套接字、等待活跃连接断开;
-
Java 应用:需注册 JVM Shutdown Hook,或通过 Spring Boot 的
SmartLifecycle或@PreDestroy执行事务回滚、连接池关闭; -
Go/Python/Node.js 服务:必须显式调用
signal.Notify或process.on('SIGTERM'),并在回调中停止 HTTP server、等待活跃请求完成、关闭 DB 连接。
⚠️ 注意:若应用启动时被 shell 封装(如 CMD ["sh", "-c", "exec myapp"]),shell 会拦截 SIGTERM,导致真正业务进程收不到信号。务必用 exec 形式:CMD ["myapp", "--config", "/etc/app.conf"]。
配合 stop-grace-period 构建完整时间窗口
STOPSIGNAL 发出后,Docker 给应用留出的“反应时间”由超时机制控制。这个时间必须覆盖你的实际清理耗时:
- Docker CLI:用
docker stop --time=45 mydb; - Docker Compose:在 service 下设
stop_grace_period: 45s; - Kubernetes:通过
terminationGracePeriodSeconds: 45设置; - 镜像构建期(可选):Dockerfile 中加
STOPSIGNAL SIGTERM+HEALTHCHECK辅助判断就绪与终态。
例如一个分片 Redis 集群节点,需同步完所有 pending slot 迁移任务再退出,实测平均耗时 32 秒——那么 stop timeout 至少设为 40 秒,避免中途被 SIGKILL 中断。
验证是否真正在走这条链路
停机后立刻检查三件事,就能确认整条信号链是否通畅:
- 容器退出码:
docker ps -a显示Exited (0)是理想状态;Exited (137)表示被 SIGKILL(即超时),说明清理太慢或未响应 SIGTERM; - 末尾日志:
docker logs myapp | tail -20查找received SIGTERM、shutting down gracefully、waiting for 3 active connections等关键词; - 进程树快照(调试用):
docker exec myapp ps fax确认 PID 1 确实是你期望的应用进程,而非 sh/bash。
不复杂但容易忽略:STOPSIGNAL 是开关,不是魔法。它只负责把“关门通知”准确送达,而门怎么关、东西怎么收、灯怎么灭——全得靠应用自己写清楚。











