服务器排障指南 · 更新于
Docker 容器一直重启怎么排查
刚把应用部署到 VPS,容器却一直显示 Restarting?重启策略只能重新拉起进程,不能修复根因。先找出进程为什么反复停下,再判断该改配置、查依赖还是处理资源不足。
1. 确认是重启循环,记下当前状态
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'
docker inspect --format 'status={{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}} finished={{.State.FinishedAt}} restarts={{.RestartCount}}' YOUR_CONTAINER
docker events --since 30m --until "$(date +%s)" --filter container=YOUR_CONTAINER --filter event=die --filter event=start
确认正在查看的是正确服务及镜像,记下故障时间和最近一次部署时间。每次执行 restarts 都在变大,或者 docker events 里 die / start 成对反复出现,就说明是重启循环。FinishedAt 是 UTC 时间。
一直重启时,括号里的数字去退出码指南查
括号里是上一次退出的退出码,只能帮你缩小下一步的范围。每个数字的完整含义和该跑的命令,见 Docker 退出码是什么意思?容器秒退、立即退出时看 0、1、125、137、139、143、255:
| 数字 | 简要含义 | 详细说明 |
|---|---|---|
| 0 | 命令正常结束;服务可能把自己放到了后台 | #exit-code-0 |
| 1 | 应用报错 | #exit-code-1 |
| 125 / 126 / 127 | Docker 没能运行 / 执行不了 / 找不到命令 | #exit-code-125、#exit-code-126、#exit-code-127 |
| 137 | SIGKILL;不能证明是内存不足 | #exit-code-137 |
| 139 / 143 | 段错误 / 收到 SIGTERM 停止 | #exit-code-139、#exit-code-143 |
2. 查重启策略和 Docker 的退避间隔
docker inspect --format 'policy={{.HostConfig.RestartPolicy.Name}} max_retries={{.HostConfig.RestartPolicy.MaximumRetryCount}}' YOUR_CONTAINER
| 策略 | Docker 怎么做 |
|---|---|
no(默认) | 从不自动重启 |
on-failure[:N] | 只在非零退出后重启,可限制最多 N 次;次数用完后容器停在 Exited |
always | 停了就重启;手动停止后,只有 daemon 或容器本身被重启时才会再拉起 |
unless-stopped | 和 always 类似,但你手动停掉的容器在 daemon 重启后也不会被拉起 |
每次重启前,Docker 会等得更久一点:间隔从 100 毫秒开始翻倍,最长 1 分钟;容器只要连续运行满 10 秒,间隔就重置。所以一个反复崩溃的容器会越来越长时间停在 Restarting,只短暂显示一下 Up。用 Compose 时,策略写在服务的 restart: 里。
改策略修不好失败的启动命令,只会改变你看到失败的频率。同一个容器不要同时用 Docker 重启策略和 systemd 这类宿主机进程管理器。详见 Docker 官方重启策略说明。
3. 只看故障附近的日志
docker logs --since 15m --tail 200 --timestamps YOUR_CONTAINER
从进程停下之前的第一条异常开始找,而不是只看最后一行;重启循环里同样的错误会反复出现。日志为空不代表没有故障:应用可能写到文件,或当前日志驱动无法提供这部分输出。此时检查应用的日志配置和服务启动记录。
- 数据库连接被拒绝:核对依赖是否运行、地址和端口是否正确(见第 4 节);容器里的 localhost 不代表另一台服务。
- 权限不足或文件不存在:核对挂载路径、文件属主、运行用户与启动参数,避免直接放宽为所有人可写。
- 配置或迁移错误:对照最近变更;先明确回滚与数据兼容性,再修改生产配置。
4. 依赖还没就绪
很常见的一种循环:应用比数据库、缓存或某个 API 先起来,第一次连接失败就退出,然后被反复拉起,直到依赖碰巧就绪。
docker compose ps
docker compose logs --since 15m --timestamps YOUR_DEPENDENCY
- Compose 里单写
depends_on,只等依赖的容器启动,不等它就绪。condition: service_healthy会等依赖的健康检查通过,前提是那个服务配了健康检查。 - 把应用用的地址和依赖在同一网络里的服务名、端口对一遍。
- 如果应用连一次失败就放弃,在应用里加一个简短的重试,通常比靠容器重启更合适。
5. 健康检查:它会重启什么、不会重启什么
docker inspect --format '{{json .State.Health}}' YOUR_CONTAINER
这条命令显示健康状态,以及最近几次检查的结果和输出。单机 Docker Engine 只会把容器标记为 unhealthy,不会因为健康检查失败去重启它。如果不健康的容器在被重启,说明是别的东西在做这件事(Swarm、编排工具或某个辅助容器),要去看那个工具的日志。
健康检查太严格,或者对启动慢的应用没设启动宽限期(start period),会让依赖它的服务一直卡在 service_healthy,或者让上面说的外部工具反复重启它。先看健康检查自己的输出,再怀疑应用。
6. 资源:内存、磁盘和端口
docker inspect --format 'memory_limit_bytes={{.HostConfig.Memory}}' YOUR_CONTAINER
docker stats --no-stream YOUR_CONTAINER
df -h
- 内存:
OOMKilled=true是 Docker 记录的内存终止线索,单有 SIGKILL 不能证明。docker stats是当前快照,还原不了故障瞬间的峰值。详见 退出码 137 与 OOMKilled。 - 磁盘:磁盘写满会让数据库和应用在启动时失败。先做 磁盘容量与 inode 检查,不要急着删文件。
- 端口:报 "port is already allocated",说明端口被别的进程或容器占着;用
sudo ss -ltnp看是谁。
7. 把证据变成下一步,而不是立即执行建议
先记录“现象 → 证据 → 待验证原因 → 最小检查”。生产环境需要明确影响范围、维护窗口和回滚方式;不要把清理数据、删除容器或扩大权限当作通用修复。
在 OpsMate(itops.sh)里,可以给 AI 这样的任务:
每个处置按风险分三档:低风险的(比如有把握的服务重启、日志轮转)会直接自动执行;中风险的(比如改配置、重建容器)会先发给你审批,30 分钟内没人处理也会自动执行;高风险的(改数据库结构、内核参数、网络和防火墙)只告警、不执行。系统拿不准的时候,会按更高一档处理。未通过安全检查的命令会被拦截且不会执行。低风险修复默认自动执行,每一步都会记录。每次让 AI 帮忙看,终端里最近的输出都会一起发到云端 AI,敏感信息请先去掉。AI 的判断需要验证;它不能仅凭一段日志保证定位准确。
说明性示例:重启后数据库还没就绪
这是说明性示例,不是真实客户案例:宿主机重启后,应用容器显示 Restarting (1),重启次数不断上涨,而数据库容器是 Up。应用每次启动后的第一条日志都是连接数据库被拒绝,数据库日志显示那几个时间点它还在初始化。Compose 里只写了 depends_on,没有健康条件。这些证据支持“依赖没就绪”的判断。可选的改法是给数据库加健康检查并用 condition: service_healthy,或者在应用里加连接重试;这些都是要先确认的变更,改完再看重启次数是否停止增长。
根据证据选择下一步
- 不知道如何理解输出?查看 同屏使用 AI 与 SSH 命令。
- 日志提示磁盘已满?先做 磁盘容量与 inode 检查,不要急着删文件。
- 拿到了数字,但不知道原因?看 Docker 退出码是什么意思?容器秒退、立即退出时看 0、1、125、137、139、143、255。
- 离开电脑后还需要跟进?查看 Telegram 告警与排查流程,并确认所需的云端凭证条件。
常见问题
Docker 容器一直重启、反复显示 Restarting,是什么原因?
重启策略只能重新拉起进程,不能修复根因:容器一直重启,是主进程每次启动后又停下了。先确认是重启循环:每次执行 docker inspect,RestartCount 都在变大,或者 docker events 里 die / start 成对反复出现。再用 docker logs --since 15m --timestamps 找停下之前的第一条异常,常见原因有依赖没就绪、权限或文件问题、配置错误和资源不足。
为什么容器重启间隔越来越长,只偶尔显示一下 Up?
这是 Docker 的退避间隔:每次重启前的等待从 100 毫秒开始翻倍,最长 1 分钟;容器只要连续运行满 10 秒,间隔就重置。所以反复崩溃的容器会越来越长时间停在 Restarting。改重启策略修不好失败的启动命令,只会改变你看到失败的频率;同一个容器也不要同时用 Docker 重启策略和 systemd 这类宿主机进程管理器。
Compose 里写了 depends_on,应用还是因为数据库没起来反复重启?
单写 depends_on,只等依赖的容器启动,不等它就绪。condition: service_healthy 会等依赖的健康检查通过,前提是那个服务配了健康检查。如果应用连一次失败就退出,在应用里加一个简短的重试,通常比靠容器重启更合适。另外核对一下地址:容器里的 localhost 是容器自己,不是另一个服务。
健康检查显示 unhealthy,Docker 会自动重启这个容器吗?
单机 Docker Engine 不会。它只把容器标记为 unhealthy,不会因为健康检查失败去重启它。如果不健康的容器在被重启,说明是别的东西在做这件事(Swarm、编排工具或某个辅助容器),要去看那个工具的日志。用 docker inspect --format '{{json .State.Health}}' YOUR_CONTAINER 能看到最近几次检查的结果和输出,先看它,再怀疑应用。
需要帮助理解排查结果?
OpsMate(itops.sh)把 SSH 终端和 AI 放在同一页,由你核对证据。每次让 AI 帮忙看,终端里最近的输出都会一起发到云端 AI,敏感信息请先去掉。
免费开始 本地凭证桌面端