Docker 容器无限重启的排查路径(Restarting 循环怎么破)

这是运维里最常见、也最容易被「看日志」误导的故障:容器状态一直是 Restarting,但 docker logs 要么没输出、要么只有一段启动成功的日志。本文给一条固定的排查路径,四步走完基本能定位。

先记住一个判断:日志为空不等于容器没启动。很多启动失败发生在容器内进程还没写任何输出之前(权限、路径、依赖缺失),这时候日志必然是空的,继续看日志会浪费大量时间。

第一步:看 exit code,它比日志信息量大

docker ps -a 的 STATUS 列里,Restarting (1) 5 seconds ago 括号中的数字就是 exit code。

# 看容器的退出码与重启次数
docker inspect <容器名> --format '{{.State.ExitCode}} {{.RestartCount}} {{.State.Status}}'

1. 看事件流(每次 exit 的准确时间)
docker events --filter container=<容器名> --since 10m
exit code含义常见原因
0正常退出容器内是短命进程,不该配 restart:always
1应用错误配置语法错、依赖缺失、启动脚本第一行就失败
2shell 用法错误entrypoint 用了不存在的命令
125docker 本身拒绝镜像不存在、参数错
126命令不可执行没执行权限,或 shebang 解释器不存在
127命令找不到entrypoint 的命令不在 PATH
137被 SIGKILLOOM 或被手动 kill
139段错误二进制不兼容(glibc 版本不符)
143被 SIGTERM收到停止信号(常因健康检查失败被重启)

137 最容易被误判:看着像「程序崩了」,其实是内存超限被内核杀掉。用 docker inspect --format "{{.State.OOMKilled}}" 确认。

第二步:日志为空时的四种原因

原因 1:权限不对(最常见,且最难猜)

容器内进程以非 root 用户运行(如 uid 999、33),但挂载进来的配置文件属主是 root 且权限 600,进程读不到配置就退出,连错误都没机会写。

# 现象:反复重启,日志为空
1. Restarting (1) 3 seconds ago

1. 验证权限与容器内 uid
ls -l /path/to/conf/file.conf
1. -rw------- 1 root root   ← 600 root,容器内 uid 999 读不到

docker inspect <容器名> --format '{{.Config.User}}'

1. 修复
chmod 644 /path/to/conf/file.conf
  • Redis 的经典坑:redis.conf 必须 644 且文件必须存在。属主不是容器内 uid 999 时,600 会 Permission denied 并无限重启
  • Nginx 的坑:证书私钥通常 600 root,若 nginx 以非 root 跑,读不到私钥直接退出
  • MySQL 的坑:数据目录权限必须是 999(mysql 用户),改成 root 会启动失败

原因 2:entrypoint 命令不存在

# 看镜像定义的 entrypoint 与 cmd
docker inspect <镜像> --format 'ENTRYPOINT={{.Config.Entrypoint}} CMD={{.Config.Cmd}}'

1. 手动跑一次,看报错
docker run --rm -it --entrypoint /bin/sh <镜像> -c "which your-command"

原因 3:配置语法错误但进程静默退出

有些服务解析配置失败时直接 exit 而不打印错误(或只写 syslog 不写 stderr)。

# 临时去掉 restart 策略,前台跑,看真实输出
docker run --rm -it <镜像> <启动命令>

1. 确认日志驱动(none/syslog 时 docker logs 拿不到内容)
docker inspect <容器名> --format '{{.HostConfig.LogConfig.Type}}

原因 4:健康检查一直失败

容器其实「活着」,但被健康检查判死,编排层反复重启。状态显示 unhealthy,配合 restart:always 就表现成循环重启。

# 看健康检查的最近输出
docker inspect <容器名> --format '{{json .State.Health}}' | python -m json.tool

1. 手动跑健康检查命令,看为什么失败
docker exec <容器名> <healthcheck 里的命令>

第三步:判断是不是依赖没就绪

容器启动时数据库还没起来,应用连不上就退出——这是 compose 编排里第二常见的原因。

# 错误:只声明 depends_on,不管对方是否就绪
services:
  app:
    depends_on:
      - mysql          # 只保证容器启动了,不保证能连上

1. 正确:用 service_healthy
services:
  app:
    depends_on:
      mysql:
        condition: service_healthy
  mysql:
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 30s   # 给初始化留时间,首次启动要建库
  • start_period 很重要:MySQL 首次启动初始化可能 30-60 秒,不设这个,健康检查在初始化期就判失败
  • 应用侧也要有重试逻辑——依赖 healthy 只是减少概率,不是绝对保证
  • docker compose up -d 后要等 ps 显示 healthy,不要立刻测应用

第四步:OOM 与资源限制

exit code 137 且日志戛然而止,基本就是 OOM。

# 确认是否被 OOM 杀掉
docker inspect <容器名> --format '{{.State.OOMKilled}}'

1. 看内存限制与实际用量
docker stats --no-stream <容器名>

1. 看宿主 dmesg 的 OOM 记录
dmesg | grep -i "killed process" | tail -5
  • 没有 swap 的机器特别容易 OOM:内存满了直接杀进程,没有缓冲
  • Go/Java 要注意堆上限(-Xmx 或 GOGC),容器限 512M 时 JVM 默认堆可能按宿主内存算
  • restart: always 加 OOM 会形成「启动→OOM→重启」死循环,CPU 一直被打满

一条命令组合排查

CN=容器名
echo "== 状态与退出码 =="
docker inspect $CN --format 'Status={{.State.Status}} Exit={{.State.ExitCode}} Restarts={{.RestartCount}} OOM={{.State.OOMKilled}}'
echo "== 最近日志 =="
docker logs --tail 30 $CN 2>&1
echo "== 健康检查 =="
docker inspect $CN --format '{{json .State.Health}}' 2>/dev/null | head -c 500
echo; echo "== 资源 =="
docker stats --no-stream $CN
echo "== 挂载 =="
docker inspect $CN --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
echo "== 事件 =="
docker events --filter container=$CN --since 10m --until 0s | tail -10

复盘:这类故障的共同点

  • 日志为空时不要继续盯日志——转而看 exit code 和权限,这两处信息量更大
  • 权限问题占多数:非 root 容器 + root 属主的配置文件,是最高频组合
  • compose 的 depends_on 不等于就绪:必须配 healthcheck + service_healthy + start_period
  • 137 先查 OOM,别浪费时间看应用日志——内存超限时应用来不及写日志
  • 先临时去掉 restart 策略再排查:它会把一次性启动错误变成无限循环,干扰观察
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇