首页/云/Docker 容器速查/docker run --init 处理信号与僵尸进程
基础命令50 条

docker run --init 处理信号与僵尸进程

在容器里注入一个 init 进程(基于 tini 的 docker-init)作为 PID 1:转发信号、回收僵尸子进程,适合把普通程序直接当主进程跑的场景。

Docker 容器速查云更新于 2026-10-13

--init 是什么

--init 在容器里注入一个轻量 init 进程(基于 tini)作为 PID 1,负责转发信号、回收孤儿进程。它适合把普通程序直接当主进程运行的场景,能解决 shell 脚本收不到停止信号、长期运行堆积僵尸进程这类问题。

基本信息

用途为容器提供小型 init,承担 PID 1 职责
语法docker run --init ...,compose 里对应 init: true
实现tini,Docker 内置的 docker-init
等价做法Dockerfile 里用 ENTRYPOINT 显式调用 tini
适用判断应用自身没做信号处理与子进程回收时才有必要

典型使用场景

  • shell 脚本作为主进程时:脚本默认不转发信号,应用收不到停止信号
  • 应用会 fork 子进程却不回收:长期运行后积累僵尸进程
  • 排查 docker stop 要等满超时才退出:多半是主进程没响应信号
  • 批处理容器确保退出时不留僵尸子进程
  • 给第三方镜像快速补上 init 能力,不必修改镜像
  • 把多个命令交给入口脚本串起来运行时,避免信号只到脚本本身

示例

示例
docker run -d --init --name job app/worker:1.4.2
docker run --rm --init alpine:3.20 sh -c 'sleep 5 & wait'
docker top job -o pid,ppid,stat,cmd     # PID 1 是 init,应用是其子进程
docker stop -t 30 job                    # 信号能转发后退出更干净

加 --init 前后的差别

方面不加 --init加 --init
PID 1应用或脚本本身tini 进程
信号转发靠主进程自己实现由 tini 转发给子进程
僵尸回收无人回收,可能堆积由 tini 负责回收
排查视角PID 1 就是应用PID 1 是 init,应用是子进程
额外开销无多一个极轻量的进程
主进程本身已正确处理信号与子进程(如 nginx 与多数守护程序)时,加 --init 意义不大,属于可选优化。
加了 --init 后排查要注意:docker top 与容器内看到的 PID 1 不再是应用本身,按应用名找主进程会找不到。
compose 里对应字段是 init: true,语义与命令行参数一致,迁移时按同样思路配置。
--init 与 --stop-signal、--stop-timeout 配合才完整:tini 负责把信号转给子进程,宽限时间决定子进程有多少时间完成清理。

易错点

  • 以为 --init 能解决所有信号问题:它只负责转发,应用自身不处理信号依旧不会优雅退出
  • 加了 --init 后误判主进程,PID 1 变成 init,按应用名判断会得出错误结论
  • 应用本身已经做好信号处理与回收,再加 --init 只是多一层进程,排查链路反而变长
  • 加了 --init 却把停止宽限设得很短,进程没来得及清理就被强杀,效果与不加没区别
  • 应用入口写成 shell 形式的字符串(而非 JSON 数组),启动后真正的进程藏在 shell 里,tini 转发信号时仍可能到不了应用

数据来源与参考

  • Docker 官方 CLI 参考:docker run --init(docs.docker.com)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌