使用Docker部署网站、数据库或其他应用时,可能遇到容器刚启动就退出,随后再次启动,始终无法正常提供服务的情况。
容器反复重启,通常需要分别检查两个问题:程序为什么退出,以及退出后由谁重新启动。 单纯增加重启次数,不能修复配置缺失、内存不足或依赖连接失败。
本文以Linux Docker Engine和Docker Compose为例。Docker命令中的web表示容器名称,Compose命令中的web表示服务名称,两者可能不同,请按实际情况替换。
1. 查看容器状态和重启次数

首先列出全部容器,包括已经退出的容器:
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
常见状态可以这样理解:
| 状态 | 含义 |
|---|---|
Up |
容器主进程正在运行,不代表业务一定正常 |
Restarting |
容器处于自动重启流程中 |
Exited |
容器主进程已经退出 |
Created |
容器已创建,但尚未成功进入运行状态 |
Up ... (unhealthy) |
主进程仍在运行,但健康检查没有通过 |
查看目标容器的重启次数和退出码:
docker inspect --format '{{.RestartCount}}' web
docker inspect --format '{{.State.ExitCode}}' web
隔一段时间再次查看,判断重启次数是否仍在增加。
RestartCount属于当前容器,不能当作完整的历史审计记录。容器被删除并重新创建后,不能继续用新容器的计数判断旧容器发生过什么。
2. 查看启动失败前的日志

执行:
docker logs --since 10m --tail 80 web
需要时间戳时,可以增加--timestamps:
docker logs --since 10m --tail 80 --timestamps web
重点寻找每次退出前重复出现的错误,例如:
-
缺少必要配置或环境变量。
-
数据库认证失败。
-
文件不存在或权限不足。
-
配置文件语法错误。
-
程序运行依赖缺失。
-
数据目录版本不兼容。
例如,日志持续提示缺少某个数据库连接配置,应先根据应用文档补齐对应配置,而不是继续重启容器。
docker logs主要读取应用输出到标准输出、标准错误的日志。应用把日志写入文件,或者使用了其他日志收集方式时,还需要查看对应日志位置。
没有日志,不代表没有错误。也可以检查Docker记录的状态错误:
docker inspect --format '{{.State.Error}}' web
3. 根据退出码缩小排查范围
退出码可以提供线索,但不能单独确定原因。
| 退出码 | 常见含义 | 排查方向 |
|---|---|---|
0 |
程序正常结束 | 是否本来就是一次性任务,启动命令是否提前结束 |
1 |
程序报告错误 | 查看应用日志和配置 |
137 |
通常对应被SIGKILL终止 | 检查OOM、人工强制停止或停止超时 |
143 |
通常对应SIGTERM终止 | 检查部署、停止操作和外部管理程序 |
| 其他非零值 | 由程序或运行环境定义 | 对照应用文档与日志分析 |
退出码137不一定意味着内存不足。 强制结束进程,或者容器在停止等待超时后被强制终止,也可能出现137。
如果退出码为0,但容器仍然反复启动,应检查:
-
是否给一次性初始化任务配置了持续重启策略。
-
启动脚本是否把服务放到后台后自行退出。
-
是否覆盖了镜像原本的启动命令。
对于需要持续运行的服务,应让实际服务进程以前台方式运行。添加一个无关的保活命令,并不能证明业务已经恢复。
4. 检查是否发生OOM或内存限制过低
执行:
docker inspect --format '{{.State.OOMKilled}}' web
docker inspect --format '{{.HostConfig.Memory}}' web
其中:
-
OOMKilled用于查看容器状态中记录的OOM标记。 -
Memory表示配置的容器内存上限,单位为字节。 -
Memory为0表示没有通过该字段设置内存硬限制,不代表宿主机资源无限。
查看宿主机内存和容器当前占用:
free -h
docker stats --no-stream web
如果容器启动后很快退出,单次docker stats可能无法捕获退出前的内存峰值。
进一步检查内核日志:
sudo journalctl -k -b --since "-30m" --no-pager
查找与故障时间对应的OOM、进程被终止或内存控制组相关记录。
OOMKilled不是完整的历史记录。容器已经重启时,当前显示false不能排除之前发生过OOM,需要结合日志和事件判断。
确认内存不足后,应评估应用实际需求、容器限额和宿主机剩余资源。可以调整并发、缓存或堆内存配置,必要时增加资源,不宜直接取消所有限制。
5. 检查启动命令、挂载目录和依赖服务
查看容器配置的入口、参数和运行用户:
docker inspect --format \
'Entrypoint={{json .Config.Entrypoint}} Cmd={{json .Config.Cmd}} User={{json .Config.User}}' web
查看挂载信息:
docker inspect --format '{{json .Mounts}}' web
重点检查以下项目:
| 检查项目 | 常见问题 |
|---|---|
| 启动命令 | 覆盖了镜像默认命令,参数或路径错误 |
| 配置文件 | 文件不存在、格式错误,或与当前版本不兼容 |
| 挂载目录 | 宿主机路径错误,挂载覆盖了镜像中的必要文件 |
| 文件权限 | 容器运行用户无法读取配置或写入数据目录 |
| 数据库、Redis等依赖 | 地址、凭据、网络或就绪状态异常 |
| 存储空间 | 空间或inode耗尽,导致初始化和日志写入失败 |
可以同时检查:
df -h
df -i
在普通桥接网络的容器中,127.0.0.1指向容器自身。数据库位于另一个容器时,通常应使用共同网络中的服务名称及容器内部端口。
使用Compose时,还要区分“已经启动”和“已经可以处理请求”。普通启动顺序不能保证数据库已经就绪;需要等待依赖健康时,应为依赖服务配置有效的健康检查,并使用condition: service_healthy。
应用本身也应具备合理的连接重试能力,以应对依赖服务运行期间的短暂中断。
6. 判断是谁在重新启动容器
查看Docker重启策略:
docker inspect --format '{{json .HostConfig.RestartPolicy}}' web
常见策略如下:
| 策略 | 主要行为 |
|---|---|
no |
不因主进程退出而自动重启 |
on-failure |
主进程以非零退出码结束时重启,可设置重试次数 |
always |
主进程退出后通常自动重启;手动停止有例外规则 |
unless-stopped |
自动恢复运行,但保留手动停止状态 |
重启策略只决定退出后的处理方式,不会修复程序本身。
如果策略是no,容器仍被反复拉起,还应检查:
-
服务器管理面板。
-
systemd服务或定时任务。
-
自动部署和更新程序。
-
外部健康监控工具。
-
Swarm、Kubernetes等编排系统。
可以查看近期Docker事件:
docker events --since 30m --until "$(date -Iseconds)" \
--filter container=web
关注die、start、kill、oom、destroy和create等事件。
Docker事件历史有保留数量限制,不能代替长期审计。如果容器ID反复变化,可能发生的是容器重建,而不是同一个容器不断重启。
7. 如何临时停止重启循环?

先保存需要的日志,并记录原来的重启策略。
对于直接由Docker管理、已经确认允许停机的目标容器,可以执行:
docker update --restart=no web
docker stop -t 30 web
第一条命令关闭该容器的自动重启策略,第二条命令停止容器。
30表示停止等待时间,单位为秒。超时后进程可能被强制终止,数据库等需要较长退出时间的服务,应按实际情况调整。
停止重启循环只是为了排查,不代表故障已经修复。
如果容器由面板或编排系统管理,应同时处理管理端的自动拉起规则,否则它仍可能重新启动或重建容器。
完成修复后,应恢复原来的策略。例如,原策略确实为unless-stopped时:
docker update --restart=unless-stopped web
docker start web
其他策略应按记录恢复,不要统一替换。Compose或面板管理的项目,也应保持其配置与预期一致。
8. 修改Compose配置后,如何正确生效?
如果问题来自Compose文件中的环境变量、启动命令或挂载设置,修改后先检查配置:
docker compose config -q
确认依赖服务已经正常运行,且允许目标服务短暂中断后,可以执行:
docker compose up -d --no-deps web
这里的web是Compose服务名称。--no-deps表示此次不启动依赖服务,因此不能用于跳过尚未解决的依赖故障。
仅执行docker compose restart不会应用Compose文件中修改后的环境变量等配置。 up会根据配置变化,在需要时重新创建服务容器。
重建前应确认业务数据已经正确挂载到数据卷或宿主机目录,并做好必要备份。只保存在容器可写层中的数据,不能依赖重建保留。
如果问题发生在镜像升级后,还应检查项目的升级说明和数据迁移要求。涉及数据库格式变化时,不要直接用旧版本程序连接已经升级的数据目录。
9. 常见问题与操作注意事项
显示unhealthy就一定会自动重启吗?
不会。普通Docker Engine的容器重启策略主要根据主进程退出处理,单纯健康检查失败不会自动触发重启。外部监控工具和编排系统可能另有处理规则。
为什么容器一直显示Up,网页仍然打不开?
Up只说明主进程存在。还需要检查服务监听地址、端口映射、反向代理、依赖服务和实际请求结果。
一直重启时无法执行docker exec怎么办?
先通过宿主机查看docker logs、docker inspect和挂载目录。容器尚未稳定运行时,不宜依赖反复尝试进入容器排查。
把重启策略改成always能修好吗?
不能。缺少配置、权限错误或内存不足没有解决时,持续重启通常只会重复同一个错误。
删除容器重新部署是不是最快?
应先保存日志、核对数据挂载并确认原因。不要把删除数据卷、执行docker compose down -v或清空Docker目录作为通用修复步骤。
10. 恢复后如何验证?
重新检查状态与重启次数:
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
docker inspect --format '{{.RestartCount}}' web
docker logs --since 5m --tail 80 web
持续观察,确认:
-
容器不再反复退出。
-
重启次数没有继续增加。
-
原来的启动错误不再重复。
-
内存、磁盘等资源保持正常。
-
网站、接口或数据库实际请求能够完成。
-
重启策略已经恢复为预期配置。
Docker容器一直重启时,应先找到程序退出的原因,再处理自动恢复规则。通过状态、日志、退出码和资源记录交叉判断,通常能够更快定位问题。
如果需要联系莱卡云技术支持,建议提供故障时间及所在时区、容器名称、镜像版本、退出码、相关日志,以及近期配置或升级记录。提交资料前,请隐藏密码、访问令牌和数据库连接凭据。