欢迎光临
专业的主机评测网站

Docker容器启动后就退出怎么办?日志、退出码与OOM排查教程

部署网站、数据库或自托管工具时,经常会遇到这样的情况:镜像已经拉取完成,容器也显示启动成功,但过几秒服务就无法访问。执行查看命令后,发现容器变成了 Exited,或者一直处于 Restarting 状态。

这类问题需要结合容器状态、应用日志和退出事件判断。配置缺失、主进程提前结束、依赖服务未就绪,以及内存不足,都可能表现为“容器启动就退出”。

本文适用于 Linux 主机上的 Docker Engine,涉及项目配置的部分使用 Docker Compose V2,即 docker compose 命令。

Docker容器启动后退出及反复重启排查教程

一、先查看容器状态和退出信息

在运行 Docker 的服务器上执行:

docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'

docker ps 默认只显示正在运行的容器,增加 -a 才能看到已经退出的容器。

常见状态可以这样理解:

状态含义与检查方向
Exited (0)主进程以成功状态结束,需要确认它是否本来就应该持续运行
Exited (1)常见于应用启动失败,具体原因需要查看日志
Exited (137)常见于进程被强制终止,需要结合 OOM、停止操作及系统记录判断
Restarting容器退出后正在按重启策略重新启动
Created容器已创建,但尚未成功进入运行状态

退出码是排查线索,不能脱离应用日志单独下结论。

先将下面的 myapp 改成实际容器名,后续命令在同一个终端中执行:

container_name='myapp'

读取详细状态:

docker inspect --format \
'Status={{.State.Status}}
ExitCode={{.State.ExitCode}}
OOMKilled={{.State.OOMKilled}}
RestartCount={{.RestartCount}}
Error={{json .State.Error}}' \
"$container_name"

重点关注:

  • ExitCode:进程退出时返回的状态。
  • OOMKilled:Docker 是否记录到与该容器相关的 OOM 终止。
  • RestartCount:容器重启次数。
  • Error:容器启动或运行过程中由 Docker 记录的错误。

这些字段反映当前容器状态,不是完整的历史故障记录。 容器已经自动重启时,还需要结合后面的日志和事件查询。

二、通过日志定位应用启动错误

查看最近 100 行日志,并显示时间:

docker logs --tail 100 --timestamps "$container_name"

重点找退出前出现的错误,以及它前面几行的上下文。

日志内容优先检查
permission denied运行用户、挂载目录权限、只读挂载及安全策略
no such file or directory文件路径、挂载位置、启动脚本及解释器是否存在
缺少环境变量或配置项Compose 的 environment、env_file 和应用配置文件
数据库连接被拒绝数据库地址、端口、网络及服务就绪状态
配置解析失败YAML、JSON 或应用配置文件的语法和参数

例如,挂载目录存在,并不意味着容器中的应用用户一定有权限读写。

可以查看容器用户和实际挂载关系:

docker inspect --format \
'User={{json .Config.User}}
{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}} RW={{.RW}}
{{end}}' \
"$container_name"

其中,Source 是挂载来源,Destination 是容器内部路径,RW=false 表示只读挂载。应根据应用要求修正具体目录的权限,避免直接对整个目录树执行 chmod 777。

如果 docker logs 没有输出,也不能判断应用没有报错。应用可能把日志写入文件,或者使用了无法通过该命令读取的日志配置。此时需要继续查看应用自己的日志位置,以及前一步的 Error 字段。

三、Exited (0):检查主进程是否提前结束

容器的主进程结束后,容器也会退出。因此,退出码为 0,可能只是启动命令已经执行完毕。

常见情况包括:

  • 容器只运行了一次性初始化脚本。
  • 启动脚本把应用放到后台,随后脚本自身退出。
  • 自定义 command 覆盖了镜像原有启动命令。
  • 执行的是打印信息、迁移数据等一次性任务。

查看实际启动程序和参数:

docker inspect --format \
'Path={{json .Path}}
Args={{json .Args}}
Entrypoint={{json .Config.Entrypoint}}
Cmd={{json .Config.Cmd}}' \
"$container_name"

如果目标是持续运行的服务,应使用应用支持的前台运行方式。

例如,自建 Nginx 镜像可以在 Dockerfile 中使用以下默认命令:

CMD ["nginx", "-g", "daemon off;"]

这是 Dockerfile 配置示例。修改后需要重新构建镜像,并更新对应容器。

使用现成镜像时,应先核对镜像文档,检查是否错误覆盖了默认的 command 或 entrypoint。对于本来就只执行一次的任务,完成后退出属于预期行为。

四、Exited (137):结合 OOM 和系统事件判断

退出码 137 不能直接等同于内存不足。

内存不足触发 OOM、手动强制结束进程,以及停止超时后被强制终止,都可能产生类似结果。

先查看 Docker 配置中的内存上限:

docker inspect --format \
'MemoryLimitBytes={{.HostConfig.Memory}}' \
"$container_name"

输出单位为字节。值为 0 表示没有通过这个配置项设置内存硬上限,并不代表可用内存无限。

查看宿主机当前内存:

free -h

在使用 systemd 的 Linux 主机上,可以查询近期内核日志:

sudo journalctl -k --since "30 minutes ago" --no-pager \
  | grep -Ei 'out of memory|oom-kill|killed process'

将记录中的时间、进程及容器相关信息,与故障发生时间进行对应。当前内存已经恢复空闲,也不能排除此前发生过 OOM。

对于反复重启的容器,还可以查询最近 30 分钟的事件:

docker events \
  --since 30m \
  --until 0s \
  --filter "container=$container_name"

关注 oom、kill、die、start 等事件及其先后顺序。Docker 历史事件有保留数量限制,查不到旧事件不代表故障没有发生。

确认内存问题后,再根据实际情况处理:

  • 容器限制过低、宿主机仍有余量:合理提高容器内存上限。
  • 宿主机整体内存不足:减少并发或其他服务占用,必要时扩容。
  • 应用内存持续增长:检查缓存、任务规模及内存泄漏。

仅增加重启次数,并不能消除持续存在的内存问题。

五、修正 Compose 配置,并让修改真正生效

如果使用 Docker Compose,应进入原项目目录,并沿用原来的配置文件、项目名和环境文件参数。

先检查配置:

docker compose config -q

正常情况下,该命令校验通过时不会输出内容;出现错误时,应先修正。校验通过只说明 Compose 配置可以被解析,不代表应用参数、数据库账号等内容一定正确。

查看项目中的服务名称:

docker compose config --services

这里的服务名可能与容器名不同。例如,服务名是 app,实际容器名可能是 project-app-1。

如果修改了环境变量、启动命令、挂载或其他 Compose 配置,仅执行 docker compose restart 不会应用这些配置变化。

只修改了 app 服务,且数据库等依赖已经正常运行时,可以执行:

docker compose config -q && docker compose up -d --no-deps app

将 app 替换为实际服务名。配置变化可能触发目标容器重建和短暂中断,执行前应确认业务数据已经持久化并做好备份。

--no-deps 不会启动依赖服务。如果数据库本身没有运行,需要先处理数据库,不能直接套用这一选项。

另外,数据库容器显示“运行中”,不一定意味着它已经可以接受连接。若日志表明应用启动早于数据库就绪,应配置合适的健康检查,并结合 depends_on 的 service_healthy 条件及应用自身的连接重试机制处理。

六、验证容器和业务是否恢复

完成修改后,查看项目状态:

docker compose ps -a

查看目标服务日志:

docker compose logs --tail 100 --timestamps app

除了确认容器处于运行状态,还需要检查:

  1. 观察时间覆盖此前的故障触发周期,容器不再反复退出。
  2. 日志中不再出现同一启动错误。
  3. 网站、接口或客户端可以完成一次实际请求。
  4. 涉及数据库和文件存储的服务,读写功能及原有数据正常。

容器能够启动,是恢复的第一步。将退出原因与日志对应起来,修正具体配置,再验证真实业务操作,才能确认这次故障已经解决。

赞(0)
【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。

专业的主机评测网站

国内/国外VPS测评、云服务器评测,从VPS或IDC商家的资质、客服水平、售后服务、VPS线路、服务器硬件、主机性能等、访问速度进行云主机、IDC测评。

联系我们联系我们