适用:使用 systemd 的 Linux 服务器、常规 rootful Docker Engine;Compose 示例使用
docker composeV2。本文为教学故障场景,错误文本和结果为示意,具体输出以现场为准。
一、遭遇情况:刚启动就重启,日志不断重复
发布后 docker ps 显示 Restarting。偶尔能进入容器,几秒后连接又断开。日志里重复出现同一条启动错误,看上去像“Docker 一直不稳定”。
本篇案例是 Nginx 配置文件里写入一个不存在的指令,进程启动即失败;容器又配置了失败重启策略,所以同一错误不断发生。重启策略在执行既定动作,真正失败的是应用初始化。
二、原因分析:重启是结果,不是根因
应用异常退出、OOM、依赖未就绪、配置错误,都可能触发重启策略。仅看到 Restarting,还不能判断是哪一种。需要把 Docker 状态与应用日志放到同一条时间线上。
另外,Compose 或外部部署平台也可能重建容器。容器 ID 一直变化与同一容器的 RestartCount 增加不同,排查时先确认是哪种行为。

三、排查思路:收集最小且有用的信息
假设容器叫 web:
docker inspect web --format 'Status={{.State.Status}} Exit={{.State.ExitCode}} OOM={{.State.OOMKilled}} RestartCount={{.RestartCount}}'
docker inspect web --format '{{json .HostConfig.RestartPolicy}}'
docker inspect web --format 'Started={{.State.StartedAt}} Finished={{.State.FinishedAt}}'
docker logs --tail 150 --timestamps web
日志不要一开始就无限 -f,快速重启可能刷掉你的观察重点。先读取有边界的最近日志,找到首次失败相关的具体信息,例如配置解析错误、缺少环境变量或依赖连接失败。
unhealthy 与“主进程退出”不是一回事。普通 Docker Engine 不会仅因为健康检查变成 unhealthy,就必然按重启策略重启容器;如果发生这种情况,还要查外部自动化控制。
四、实践:用有限重试复现配置错误
在同一个 Bash 会话中执行,下列临时目录只保存实验 Nginx 配置:
lab_dir=$(mktemp -d /tmp/dt09.XXXXXX)
printf '%s\n' 'events {}' 'http { broken_directive on; }' > "$lab_dir/nginx.conf"
docker run -d --name dt09-loop --restart=on-failure:3 --mount "type=bind,src=$lab_dir/nginx.conf,dst=/etc/nginx/nginx.conf,readonly" nginx:stable-alpine
docker logs --tail 60 --timestamps dt09-loop
docker inspect dt09-loop --format 'Status={{.State.Status}} Restarts={{.RestartCount}} Exit={{.State.ExitCode}}'
日志预期指向未知指令 broken_directive。因为设置了最多 3 次失败重试,观察时可能是 Restarting,也可能已经达到限制后 Exited;不应要求读者恰好截到某一瞬间。
实验不发布任何宿主机端口,不会接管线上 Web 入口。
五、修复实践:先预检,再重新启用服务
对这个明确的实验容器,关闭重启策略并停止,减少诊断噪声:
docker update --restart=no dt09-loop
docker stop dt09-loop
真实业务操作前先记录原策略,并确认变更范围。若由 Compose 管理,最终修复还要写回 Compose 文件,否则后续部署可能恢复旧配置。
将实验配置修正为一个最小可用服务。本例直接写入原文件,保持文件挂载目标清楚:
cat > "$lab_dir/nginx.conf" <<'EOF'
events {}
http {
server {
listen 80;
location / { return 200 "ok\n"; }
}
}
EOF
docker run --rm --mount "type=bind,src=$lab_dir/nginx.conf,dst=/etc/nginx/nginx.conf,readonly" nginx:stable-alpine nginx -t
配置预检通过后,再启动原实验容器:
docker start dt09-loop
docker logs --tail 30 dt09-loop
docker exec dt09-loop wget -qO- http://127.0.0.1/
docker inspect dt09-loop --format 'Status={{.State.Status}} Restarts={{.RestartCount}}'
预期得到 ok,容器保持运行。这里的检查证明应用实际监听并能响应,而不只是“配置语法通过”。
确认稳定后,可将实验的失败重试策略恢复为 docker update --restart=on-failure:3 dt09-loop。生产容器应恢复原先经过评估的策略,而不是统一套用本示例。
六、验证与总结:重启次数要停止增长
隔一段时间再次检查状态和重启次数,确认没有继续增长;核对应用请求、相关依赖和最近日志。不要把一次 docker start 返回容器名视为修复完成。
如果改完仍反复失败,回到新的错误信息继续处理,而不是不断提高重试次数。配置发布应增加应用自身的预检步骤,能在上线前发现的语法错误,就不要留给重启策略反复放大。
本篇的排查闭环是:确认谁在重启 → 捕获具体启动错误 → 暂停噪声 → 验证配置 → 启动并请求服务 → 观察稳定性。重启策略负责恢复尝试,不负责修复配置。