可通过配置 docker-compose.yml 的 stop_signal 字段指定退出信号(如 sigusr2),使微服务捕获该信号执行清理逻辑实现优雅退出;需确保进程为 pid 1 并在代码中正确监听响应。

可以通过在 docker-compose.yml 中为服务配置 stop_signal 字段,指定容器内主进程接收的退出信号(如 SIGTERM、SIGUSR2 等),从而让微服务代码捕获该信号并执行清理逻辑,实现优雅退出。
stop_signal 的作用与默认行为
Docker Compose 默认向容器主进程发送 SIGTERM 信号来终止服务。如果服务未处理该信号,或处理不及时,Compose 会在 10 秒后强制发送 SIGKILL 杀死进程。设置 stop_signal 可以改用其他信号(例如某些 Go 或 Node.js 应用习惯监听 SIGUSR2 或 SIGHUP),让应用按自身逻辑响应退出流程。
- 该字段只影响
docker compose stop和docker compose down时的停止行为 - 不影响
docker stop容器本身的信号发送逻辑(除非通过--signal显式指定) - 必须确保微服务进程实际能接收并响应所选信号(例如非 PID 1 进程需用
exec启动,避免被 shell 拦截)
在 docker-compose.yml 中配置 stop_signal
在对应服务的配置块中添加 stop_signal,值为信号名称(不带 SIG 前缀)或数字:
services:
api:
image: my-api:latest
stop_signal: SIGUSR2
# 或写成数字形式:stop_signal: 12
注意:信号名称需与目标语言运行时支持的信号一致。例如 Python 的 signal 模块支持 signal.SIGUSR2,Go 的 os.Signal 也支持 syscall.SIGUSR2。
微服务内部需正确捕获并响应信号
仅配置 stop_signal 不够,服务代码必须主动监听对应信号,并在收到后完成资源释放、连接关闭、队列清空等操作,再主动退出:
- Node.js 示例:使用
process.on('SIGUSR2', () => { cleanup(); process.exit(0); }) - Go 示例:用
signal.Notify(c, syscall.SIGUSR2)监听,收到后调用http.Server.Shutdown()等 - Java(Spring Boot):可通过
@EventListener监听ContextClosedEvent,但更推荐用Runtime.getRuntime().addShutdownHook()配合外部信号触发 - 确保主进程是 PID 1(推荐用
exec "$@"启动命令),否则信号可能无法送达
验证优雅退出是否生效
启动服务后,手动触发停止并观察日志输出,确认是否执行了预期的清理逻辑:
- 运行
docker compose down,检查服务日志中是否有“shutting down…”、“gracefully closing…” 类提示 - 用
docker compose ps观察状态是否短暂处于Stopping而非立即Exit - 若服务卡住超时,说明信号未被捕获或清理阻塞,需检查信号注册位置和阻塞点(如未设超时的数据库连接等待)











