--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 负责把信号转给子进程,宽限时间决定子进程有多少时间完成清理。