首页 > Technology > 正文

Docker 容器一直重启或退出怎么办?系统排查指南

fenij 2026-07-28 209 Technology

docker ps 里容器状态一直显示 Restarting (1) xx seconds ago,或者刚 up 没多久又变成 Exited——这是用 Docker 时最常碰到的故障之一。容器反复重启,本质就一句话:容器主进程退出了,而重启策略又把它拉起来,于是循环。排查的思路也很直接,就是去找”主进程到底为什么退出”。下面按步骤给出能直接复制的命令。

容器重启原因对比

状态码 含义 排查方向
Exit 0 正常退出但 restart:always 检查是否应该用 restart:unless-stopped
Exit 137 OOM 被杀 docker inspect 看 OOMKilled
Exit 1 应用报错退出 docker logs 看错误
Exit 255 入口脚本错误 检查 entrypoint / cmd
Restarting 反复重启 看 logs 是否启动即崩

排查流程

1docker ps -a 看状态

2docker logs –tail 50

3docker inspect 看 OOMKilled

4docker events 看重启频率

第一步:看容器日志,绝大部分问题在这一步就能看出来

docker logs --tail 100 容器名
docker logs -f 容器名   # 实时跟踪重启瞬间的输出

常见的日志线索有这些:配置文件路径写错、数据库连不上、端口被占用、缺环境变量、应用自己抛异常。日志能看懂的,直接回去修应用问题就行;日志为空或者看不出名堂的,继续下一步。

第二步:查退出码,判断退出类型

docker inspect 容器名 --format '{{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}'

退出码对照如下:

  • 0:进程正常结束——通常是容器里没有前台常驻进程(见第四步);
  • 1:应用报错退出——回去细看 docker logs;
  • 137:被 SIGKILL 杀掉,若 OOMKilled 为 true 就是内存超限;
  • 126/127:启动命令不可执行/找不到——检查 entrypoint 和 command 的拼写;
  • 139:段错误,多半是程序或依赖库自己的缺陷。

第三步:内存不足(退出码 137)的处理

先确认宿主机整体内存和容器的限制:

free -h
docker stats --no-stream

如果容器设了 -m 内存上限,而且经常打满,要么调大限制,要么优化应用(比如给 Java 应用设 -Xmx 小于容器限制,给 MySQL 容器调低 innodb_buffer_pool_size)。宿主机整体内存不够时,可以临时加 swap 应急:

fallocate -l 2G /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile

第四步:退出码 0 却一直重启?主进程没有常驻

容器要求 PID 1 是一个前台常驻的进程。下面这些写法都会”启动即退出”:入口命令是一条执行完就结束的脚本、nginx 没加 daemon off、用了 service xxx start 这类后台化命令。修复示例:

# 错误:CMD service nginx start
# 正确:
CMD ["nginx", "-g", "daemon off;"]

调试时可以先用 sleep 把容器保住,再进去手动跑命令看报错:

docker run -it --entrypoint /bin/sh 镜像名
# 容器内手动执行原启动命令,直接观察报错

第五步:检查重启策略与依赖顺序

docker inspect 容器名 --format '{{.HostConfig.RestartPolicy.Name}}'

如果应用依赖数据库,而数据库容器还没就绪应用就启动失败,就会形成”启动-失败-重启”的循环。docker-compose 里应该用 healthcheck + depends_on 的 condition: service_healthy,而不是裸的 depends_on。另外磁盘写满(用 df -h 检查)也会让容器反复起不来。

常见问题

如何暂时阻止容器无限重启,方便排查?
先执行 docker update --restart=no 容器名docker stop,排查修好后再改回 always 或 unless-stopped。

docker logs 什么都没有输出怎么办?
说明主进程在打印任何内容之前就退出了,多半是入口命令本身有误。用上面那个 –entrypoint /bin/sh 的方式进容器,手动执行启动命令来定位。

容器在宿主机重启后全部变成 Exited 正常吗?
如果重启策略是 no 就属于正常现象。希望开机自启的容器,应该设成 –restart unless-stopped。

如果你的容器问题按上面的步骤还没解决,欢迎到 fenij.com 评论区贴出 docker logs 和退出码,我们帮你一起看。

实操补充:如何正确地手动重启容器

排查完原因要重启时,命令用错也会踩坑。最常用的是 docker restart 容器名,它先发 SIGTERM 优雅停止、默认等 10 秒再 SIGKILL。如果你的服务关得慢(比如正在落盘),加个超时:docker restart -t 30 容器名 给足 30 秒。

在 docker-compose 项目里别直接 restart 容器,用 docker compose restart 服务名,它会按依赖顺序重启。下面这张表把几种「重启」的区别一次说清:

命令 作用 会重读配置吗
docker restart停掉再拉起容器
docker stop + start等价于 restart
docker compose restart按依赖重启服务
docker compose up -d重建并启动(改了 yml 用它)

restart 不会重新读配置。你改了 docker-compose.yml 想让改动生效,必须跑 docker compose up -d,光 restart 没用——这坑过不少人。

数据会不会丢?容器本身是无状态的,真正的数据在 volume 里。跑 docker inspect 容器名 --format '{{json .Mounts}}' 看挂载:凡是挂了 volume 或 bind mount 的目录,重启甚至删容器都不丢;只有写在容器可写层(没挂出来的部分)的临时文件会随容器消失。

开机自启:创建容器时加 --restart unless-stopped,或对已有容器执行 docker update --restart unless-stopped 容器名,机器重启后会自动拉起。

延伸答疑

docker restart 和 stop 再 start 有区别吗?
没本质区别,restart 就是一步到位的 stop+start,还自带 10 秒优雅停止超时,更省事。

重启后端口连不上 / IP 变了?
桥接网络下容器每次重启可能拿到新 IP,别在别的服务的配置里写死容器 IP,改用容器名或服务名做内网 DNS 解析;端口映射(-p)是固定的,外部照常用宿主机端口访问。

改了配置 restart 不生效?
restart 只读内存里当前进程状态,不读磁盘上的 compose 文件。改完 yml 跑 docker compose up -d 让它重新创建容器。

怎么让容器开机自动重启?
docker update --restart unless-stopped 容器名;compose 项目在 yml 的 service 下加 restart: unless-stoppedup -d

相关完整手册

系统化的排查与配置思路,建议顺手收藏这几篇完整手册: