Tini是Docker官方推荐的轻量级init,核心解决PID 1进程收信号、转信号、收僵尸问题;支持apt/apk安装、ENTRYPOINT声明、--init运行时启用及exec优化等方案。
核心是让 pid 1 进程能收信号、转信号、收僵尸。直接用 shell 启动应用或应用自身不处理 sigterm,都会卡在 docker stop 的 10 秒等待里,最后被 sigkill 强杀。
用 tini 作为轻量 init
tini 是 Docker 官方推荐方案,体积小、零依赖、自动转发所有信号、自动回收僵尸进程。
- Debian/Ubuntu 镜像中安装:
RUN apt-get update && apt-get install -y --no-install-recommends tini && rm -rf /var/lib/apt/lists/* - Alpine 镜像中安装:
RUN apk add --no-cache tini - 声明入口点:
ENTRYPOINT ["/sbin/tini", "--"] - 后续 CMD 正常写你的命令,比如:
CMD ["python", "app.py"]
用 exec 替换 shell(单进程适用)
如果确认容器只跑一个前台进程,且该进程本身支持 SIGTERM(如多数 Go/Python/Node.js 服务),可避免引入额外 init,直接让应用成为 PID 1。
- ❌ 错误写法(shell 占 PID 1,不转发信号):
CMD ["sh", "-c", "python app.py"] - ✅ 正确写法(exec 替换 shell 进程):
CMD ["sh", "-c", "exec python app.py"] - 或者更简洁地写成:
ENTRYPOINT ["exec", "python", "app.py"]
启动时加 --init 参数(运行阶段补救)
不改镜像也能快速生效,Docker 自带的轻量 init(基于 tini)可直接启用。
- 启动容器时加参数:
docker run -d --init --name myapp myimage - 效果等同于镜像内配置了 tini,但优先级低于镜像自身的 ENTRYPOINT
验证是否修复成功
别只看容器停没停,要确认信号真传到了应用。
- 进入运行中的容器:
docker exec -itsh - 查 PID 1 是什么:
ps -p 1(应为 tini 或你的应用,不是 sh/bash) - 手动发 SIGTERM:
kill -TERM 1 - 观察容器是否秒退:
docker ps | grep,若立即消失说明信号链通了











