Docker 容器排障与调试实战:退出码、OOM、exec 与调试工具链

Docker 容器排障与调试完整实战:定位容器为什么不起来(退出码/启动失败/依赖)、进入容器调试(exec/nsenter/调试镜像)、OOM 与资源问题、镜像拉取与构建失败、日志与事件排查、网络与端口问题,以及一套可复用的排障路径与工具链。

容器"起不来、起来就崩、网络不通、拉不到镜像"——排障最怕乱试。Docker 排障有清晰的信息源:退出码、日志、事件、inspect、exec。本指南给出一套可复用的排障路径:先看"容器为什么退出"(退出码),再看"它说了什么"(日志),最后"进去看"(exec/调试),并覆盖 OOM、镜像、网络等高频问题。

关键概念:容器排障的信息金字塔——docker ps -a(状态)→ docker logs(它说了什么)→ docker inspect(配置与挂载)→ docker events(发生了什么)→ docker exec(进现场)。按这个顺序,别先乱删重建。


1. 先定位:容器为什么退出

1.1 从状态看退出码

docker ps -a            # 看所有容器状态
docker inspect -f '{{.State.ExitCode}} {{.State.Error}}' <container>
docker inspect -f '{{.State.Status}} {{.State.OOMKilled}}' <container>
常见退出码:
  0     正常退出(任务型容器完成/主动 exit)
  1     程序错误退出(应用自己 exit(1))
  125   docker run 本身错误(参数/镜像不存在)
  126   命令无法执行(文件不存在/无执行权限)
  127   命令找不到(command not found)
  128+  被信号杀死(128 + 信号号)
  137   = 128+9,SIGKILL → 常见 OOM 被内核杀掉
  139   = 128+11,SIGSEGV 段错误
  143   = 128+15,SIGTERM 正常终止

ℹ️ 核心:退出码是第一线索。137/OOMKilled=true → 内存问题;127 → 命令/路径问题;125 → 运行参数问题。先读码,再对症。

1.2 启动失败的常见原因

起不来(Restarting / Exited)的排查顺序:
  1. 命令/ENTRYPOINT 不存在或拼错(exit 126/127)
  2. 依赖服务没起来(数据库连接失败,看日志)
  3. 挂载卷权限/路径错误
  4. 端口占用(bind: address already in use)
  5. 资源不足(内存不够 OOM)
  6. 环境变量缺失/配置错误

2. 它说了什么:日志与事件

2.1 看日志

docker logs --tail 100 <container>     # 最后 100 行
docker logs -f <container>             # 实时跟随
docker logs --since 10m <container>    # 最近 10 分钟

# 应用写 stdout/stderr 才会进 docker logs
# 写到文件/别处的日志要去容器里看或看挂载

2.2 看事件(了解发生了什么)

docker events --since 30m
# 输出:container create / start / die / oom / kill 等事件

# 只看某容器
docker events --filter container=<name>
events 的价值:
  看 OOM、重启、kill 等"状态变迁",配合日志定位根因
  比只看最终状态更能还原过程

3. 进去看:exec 与调试镜像

3.1 docker exec 进入运行容器

docker exec -it <container> bash       # 交互式 shell
docker exec <container> ps aux         # 执行任意命令
docker exec <container> cat /etc/nginx/nginx.conf
注意:
  - exec 需要容器仍在运行
  - 容器里可能没有 shell/调试工具 → 用调试镜像
  - exec 是"进现场",别在 exec 里乱改(重启即失)

3.2 容器里没有工具怎么办

方案一:用调试镜像共享网络/命名空间
  docker run -it --rm --network container:<target> \
    --pid container:<target> \
    nicolaka/netshoot bash
  # netshoot 自带 curl/ss/tcpdump/dig 等排查工具

方案二:nsenter 从宿主机进入容器命名空间
  pid=$(docker inspect -f '{{.State.Pid}}' <container>)
  nsenter -t $pid -m -u -i -p bash

方案三:拷贝文件进去/出来
  docker cp <container>:/etc/app/config.json ./config.json
  docker cp ./fix.sh <container>:/tmp/

4. OOM 与资源问题

4.1 定位 OOM

# 确认是否被 OOM 杀掉
docker inspect -f '{{.State.OOMKilled}}' <container>

# 宿主机 OOM 记录(内核日志)
dmesg | grep -i "out of memory" | tail
journalctl -k | grep -i oom
OOM 两种:
  容器被 cgroup 限额杀(内存超过 --memory)→ OOMKilled=true
  宿主机整体内存不足 → 内核随机杀进程(可能杀到别容器)
  → 对症:前者调大容器 limit;后者给节点扩容/腾内存

4.2 资源排查

docker stats --no-stream        # 看每个容器资源占用
# 确认:谁吃内存、谁打满 CPU

# 进程层面的容器内排查
docker exec <container> ps aux --sort=-%mem | head
资源问题的治理:
  - 明确 limits(防止单容器拖垮)
  - 定位是"业务峰值"还是"内存泄漏"(看是否持续增长)
  - 泄漏 → 修代码/加 monitoring;峰值 → 容量规划

5. 镜像与构建问题

5.1 拉取失败

常见拉取失败:
  - 网络问题 / 认证失败 / 权限不足
  - 镜像不存在或 tag 拼错
  - registry 无法访问(自建/内网代理)

排查:
  docker pull 报错信息、检查 /etc/docker/daemon.json 的 registry-mirrors
  docker login 检查认证
  DNS / 代理 / 防火墙逐层看

5.2 构建失败

常见构建失败:
  - 某 RUN 命令报错(网络下载失败、依赖装不上)
  - 缓存问题(陈旧缓存导致行为异常)→ --no-cache 重试
  - COPY 源文件不存在
  - 资源不足(构建内存不足 OOM)

调试:
  docker build --no-cache .           # 绕开缓存
  docker build --progress=plain .     # 完整输出(不看省略)
  docker build --target <stage> .     # 只构建到某阶段

6. 网络与端口问题

常见网络排查:
  - 端口不通:确认 -p 映射、容器内监听、防火墙
  - 容器间不通:网络模式/自定义网络/DNS 解析
  - 出网失败:DNS、代理、路由

工具链:
  docker port <container>            # 端口映射情况
  docker exec <container> ss -tlnp   # 容器内监听端口
  docker exec <container> ping/dig/curl   # 连通性
  # 或用 netshoot 调试镜像(tcpdump/dig/curl 齐全)
# 快速验证端口映射
curl -v http://localhost:<published>/
# 不通时:看容器内是否真在监听 + 防火墙是否放行

7. 一套可复用的排障 SOP

标准排障路径(按顺序,不跳步):
  1. docker ps -a        —— 状态与退出码
  2. docker logs --tail   —— 应用说了什么
  3. docker inspect       —— 配置/挂载/环境
  4. docker events        —— 状态变迁/OOM/kill
  5. docker stats         —— 资源占用
  6. docker exec          —— 进现场(或 netshoot)
  7. 定位根因 → 对症修复 → 记录复盘

快速定位口诀:
  先看退出码,再读日志,进去看现场,最后查事件
避坑提醒:
  - 别一上来就 docker rm -f 重建(丢失现场证据)
  - 修复前先确认根因(改一行就能省去反复)
  - 高发问题沉淀为 checklist/SOP

8. 常见避坑速查

现象排查点对策
退出码 137OOM调 limit / 定位泄漏
退出码 127命令不存在检查 ENTRYPOINT/路径
起不来依赖没就绪加 wait/healthcheck
日志为空应用写文件没写 stdout进容器/看挂载
网络不通映射/监听/防火墙逐层验证
拉取失败认证/网络/mirror逐项排查

9. 最佳实践清单

□ 启动即配 --restart 与 HEALTHCHECK,让"起不来"尽早暴露
□ 应用日志统一写 stdout/stderr(进 docker logs)
□ 排障按 SOP 顺序:状态→日志→inspect→events→stats→exec
□ 准备好调试镜像(netshoot 等),应对容器无工具
□ 明确资源 limits,OOM 有边界可查
□ 构建失败用 --no-cache/--progress=plain 复现
□ 高发问题沉淀为排查手册
□ 别乱删容器,先留证据

一句话原则

排障不是乱试,
而是"退出码给方向、日志给证据、现场给真相"的层层逼近。

小结

Docker 排障与调试,本质是用正确的信息源层层逼近根因:退出码告诉方向(137=OOM、127=命令缺失)、日志提供应用证据、inspect/events还原配置与变迁、exec/调试镜像进入现场取证。落地记住五件事:先看退出码再读日志、进现场用 exec 或 netshoot、OOM 用 OOMKilled + dmesg 定位、构建失败用 –no-cache 复现、沉淀一套排障 SOP。当排障从"靠感觉重试"变成"有路径有工具",Docker 环境里的每一次事故都会更快止血、更准定位、不再反复。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「DevOps」更多文章

  1. 备份与容灾自动化:RPO/RTO、Velero、PITR 与恢复演练
  2. 配置漂移与安全基线:IaC漂移检测、CIS合规、供应链安全与密钥轮换
  3. 内部开发者平台(IDP)工程化:Backstage、Golden Path 与自服务能力