Docker 容器起不来/反复重启:一键排查(ExitCode、OOMKilled、健康检查误杀)

典型现象:

  • docker ps 看不到容器(很快退出)
  • docker ps -a 看到 Exited (1) / Restarting / unhealthy
  • 业务间歇可用,随后又挂

目标:把问题从“在重启”缩到:为什么退出(ExitCode)是不是 OOMKilled是不是健康检查误杀是不是依赖未就绪


0. 一键排查(推荐)

在目录 docker/ops-triage/ 下:

chmod +x bin/triage
./bin/triage restart <container-name-or-id>

1. 原理:Docker 的“重启”来源不止一个

Docker restart policy

外部编排

进程自己退出

内核/容器 OOM

健康检查

容器重启

是谁触发?

RestartPolicy=always/on-failure

K8s/Swarm/脚本

ExitCode!=0

OOMKilled/SIGKILL

unhealthy -> 被重建/重启

所以第一步永远是把状态与退出原因取出来(inspect + logs)。


2. 真实故障场景库(典型现象 → 下一步动作)

场景 1:ExitCode=1/2 等非 0(应用主动退出)

常见原因:配置缺失、启动参数错误、依赖不可达、权限不足。

下一步动作

  • docker logs --tail 200 <c> 看最后错误行
  • docker inspect <c> 看启动命令、环境变量、挂载

场景 2:ExitCode=137 或 OOMKilled=true(内存被杀)

下一步动作

  • 查容器内存限额(编排参数 / docker run -m)
  • 查宿主机 OOM:dmesg -T | egrep -i 'oom|killed process' | tail
  • 如果是 JVM/进程内 OOM:回到应用内存治理(JVM/Lang)

场景 3:容器状态 unhealthy(健康检查误杀或误判)

下一步动作

  • docker inspect 看 Healthcheck 配置与失败次数
  • 放宽阈值:初始延迟、超时、失败次数
  • 区分 readiness vs liveness(编排环境尤其重要)

场景 4:端口绑定失败导致启动即退出

现象:日志里出现 bind 失败或 Address already in use。

下一步动作

  • 查宿主机端口冲突:./bin/triage port <port>
  • 查容器内监听是否正确(必须监听 0.0.0.0 而不是 127.0.0.1)

场景 5:依赖未就绪(DB/RPC)导致启动自检失败

下一步动作

  • 启动时依赖检查要可重试并有超时
  • 健康检查不要过度激进,避免把下游打成雪崩

3. 值班 Checklist

  • docker ps -a:Status/ExitCode
  • docker inspect:OOMKilled、RestartPolicy、Healthcheck
  • docker logs:最后错误行
  • 宿主机:dmesg 是否 OOM/I/O error
  • 端口/依赖:是否冲突/不可达

4. 小结

容器反复重启的最快闭环是:inspect 定位退出原因 → logs 找最后错误 → 判断 OOM/健康检查/端口/依赖 → 再决定是改资源、改探针、改配置还是修代码

更多推荐