Docker容器启动后退出或反复重启怎么办
适用于已安装Docker Engine的Linux服务器。容器显示“Exited”或“Restarting”时,先确定是程序正常结束、应用报错,还是启动阶段就失败。下面的检查在Docker所在主机执行,需要已有Docker操作权限;所有命令都针对同一个容器。
1. 找到容器,保存状态和最近日志
docker ps -a --format 'table {{.ID}}\t{{.Names}}\t{{.Status}}'
-a会列出已停止的容器。找到故障容器的名称或ID,把下面的baoleyun-demo替换成实际值;后续命令在同一终端执行。
container_id='baoleyun-demo'
docker container inspect --format '状态={{.State.Status}}
退出码={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}
开始={{.State.StartedAt}}
结束={{.State.FinishedAt}}
重启次数={{.RestartCount}}
启动错误={{.State.Error}}
健康检查={{if .State.Health}}{{.State.Health.Status}}{{else}}暂无健康状态{{end}}' "$container_id"
docker logs --tail 200 --timestamps "$container_id"
先保存这些输出,再做重启操作。状态字段反映当前或最近一轮运行,持续重启时会变化。日志里的Z表示UTC时间,与北京时间相差8小时,核对故障时间时要统一。
日志为空也要继续查:应用可能写入自己的日志文件;远程日志驱动关闭本地缓存后,docker logs可能读不到内容。“暂无健康状态”可能是没有配置健康检查,也可能是容器尚未运行,不能据此判断应用健康。
2. 退出码只能缩小范围
| 看到的结果 | 下一步检查 |
|---|---|
Exited (0) |
进程正常结束。备份、迁移等一次性任务可能已经完成;若它本应是常驻服务,检查启动脚本是否把服务放到后台后自行退出。先确认任务用途,避免重复执行已完成的业务操作。 |
Exited (1)等其他非零码 |
查看退出前的最后一段日志,优先处理缺少配置、连接依赖失败等明确错误。不同应用对退出码的定义不同。 |
Exited (137) |
常见于收到SIGKILL。内存不足、人工强制停止、停止超时后被强制结束都可能出现137;需结合OOMKilled和同一时间的系统记录判断。 |
Exited (143) |
通常与SIGTERM有关。先核对当时是否正在停止、部署或维护,不能直接认定为崩溃。 |
created,且“启动错误”有内容 |
从该错误入手,例如宿主机端口被占用、挂载路径不存在。应用可能根本没启动,因此未必有应用日志。 |
OOMKilled=true说明Docker记录到了OOM相关事件,应检查容器内存限制和服务器内存。false也不能单独排除更早发生的内存问题;对照故障时间查看系统日志,再按内存不足排查教程检查。
3. 按日志核对端口、挂载和依赖
下面只读取排查需要的配置字段,不输出整个容器配置:
docker container inspect --format '端口={{json .HostConfig.PortBindings}}
挂载={{json .Mounts}}
运行用户={{.Config.User}}
内存上限={{.HostConfig.Memory}}
重启策略={{json .HostConfig.RestartPolicy}}
日志驱动={{.HostConfig.LogConfig.Type}}' "$container_id"
| 日志或启动错误 | 具体处理方向 |
|---|---|
port is already allocated或绑定端口失败 |
核对输出中的HostPort,按端口监听检查方法找到占用者。确认用途后调整当前服务的端口映射;不要直接结束不明进程。 |
路径不存在、文件类型不符、Permission denied |
核对挂载的Source(主机路径)与Destination(容器路径)、文件或目录类型,以及RW是否允许写入。按镜像要求核对运行UID/GID和目录权限。挂载覆盖镜像中的目录后,原有文件会被遮住;重装应用未必能解决路径配错。 |
| 数据库或其他依赖连接失败 | 检查依赖容器日志及就绪状态,再核对应用使用的地址、端口和账号。Compose的普通启动顺序不保证数据库已能接受连接;需要就绪等待的应用,应配置相应健康检查与service_healthy条件。 |
内存上限以字节计;该字段为0表示未单独设置硬上限,服务器实际内存仍然有限。重启策略也不会修复配置错误:on-failure只针对非零退出码,手动停止还会影响后续自动启动行为。单机Docker Engine的重启策略由进程退出触发,仅变为unhealthy不会触发该策略。
4. 修正后,只操作对应服务并复查
如果已修正挂载文件或外部依赖,确认该容器应长期运行且当前已停止,可启动这个容器,再重新读取第一步的状态和日志:
docker start "$container_id"
如果原来使用Compose部署,修改了环境变量、端口或挂载配置,单纯docker compose restart不会应用这些变更。先确认数据已有备份且保存在卷或挂载中、依赖服务已就绪。改卷名或挂载的Source/Destination不会自动迁移数据,重建前核对新配置仍指向需要保留的数据;容器可写层不能当作持久化备份。然后在原项目目录执行下列命令;把app替换为Compose中的服务名,并沿用原部署的-f、-p、--env-file等参数。
docker compose config --quiet && \
docker compose up -d --no-deps app
&&保证配置校验通过后才执行更新。后半条命令可能重建所选服务容器;若ID变了,重新从docker ps -a取得新ID,再设置container_id。不要把容器ID填在Compose服务名的位置。
复查应覆盖原来的故障周期:例如此前每隔10分钟退出一次,启动后只观察几十秒不够。确认同一容器的启动时间稳定、重启计数不再增加、日志没有重复原错误,并完成一次实际业务访问。重建后计数归零、本来没有健康检查、暂时显示“Up”,都不足以单独判断修复成功。
仍无法定位时,提交故障发生时间、容器状态和对应日志片段。按日志脱敏方法去掉密码、令牌与个人信息,不要直接公开完整docker inspect或.env文件。
依据:Docker官方容器状态、日志、存储、重启策略及Compose文档;核对日期:2026年11月4日。