12进阶:出事了怎么查

第 12 关 出事了怎么查

本关的产出:拿到一个起不来、退得快、或者连不上的容器,能在十分钟内定位到出错的那一层。

12.1 先看它是死是活

第一眼看两样:

  • STATUS:Up 3 seconds(在跑)、Exited (1) 2 minutes ago(退了)、Restarting(一直在重启)。
  • 退了的,看括号里那个数——退出码。

退出码怎么读:

码意思
0正常结束(一次性的活儿干完了)
1程序自己报错退了
125docker run 本身就没跑起来(参数错)
126要跑的命令不可执行
127要跑的命令找不到
137被 SIGKILL 打死(128+9)——常见于内存超限,或 stop 等超时后被强杀
143被 SIGTERM 打倒(128+15)

137、143 是「信号编号 + 128」——第 8 关讲的信号,在这儿成了读数。

12.2 退了?先看日志

  • 127:镜像里根本没有这个命令——CMD/ENTRYPOINT 写错了,或者你覆盖的那个命令不存在。
  • 1:程序自己的报错,日志里通常写着。
  • 日志是空的:要么它还没来得及输出就死了,要么它把日志写进了自己的文件、没往 stdout 写(第 11 关)。

12.3 docker inspect:字段怎么读

现在轮到第 2 关那个「输出很长、没有解释」的东西。它打出来是一整段 JSON,不用全看,记住几个地方就够。

先看 State:

字段看什么
Status对应 docker ps 的 STATUS
ExitCode就是 12.1 那张表
Error启动失败的原因,往往比日志直接
OOMKilled是不是内存超限被杀的(对得上 137)

再看 Config,它是「这条容器最终拿到的配置」:

字段是什么查什么
Config.Cmd最终跑的启动命令是不是你想跑的(被镜像名后面的参数顶掉了吗)
Config.Entrypoint入口程序有没有多套一层壳(第 8 关)
Config.Env环境变量你 -e 给的值进去了吗
Config.ExposedPorts声明的端口服务该在哪个端口
Mounts挂载目录真的挂上了吗、挂的是哪儿

一个很好用的观察:传 <容器> 进去时,Config.Env 是镜像默认值和你 -e 的值合并后的结果——一眼看得出这条容器最终拿到了什么,不用猜。

只看一项,用 --format,别在一大段 JSON 里翻:

Cmd、Entrypoint 的含义第 3 关和第 8 关讲过,这里不重讲——本关只讲拿它们查什么。

12.4 连不上:先分三层

「A 连不上 B」不是一个问题,是三个。按顺序查,每层都有证据:

  1. 名字没解析——A 根本不知道 B 是谁。
    • docker exec A getent hosts B:解析不出来,就是这层。
    • docker exec A cat /etc/resolv.conf:是不是 127.0.0.11(第 5 关)。
    • 两个容器在不在同一张网:docker inspect A 的 NetworkSettings.Networks。
  2. 解析到了,但网络不通——包发不出去。
    • 拿上一步的 IP 直接连:连不上,就是这层。
    • 常见原因:一开始就没接上,或者接上之后又被 docker network disconnect 摘了(命令见第 5 关 5.3)。
  3. 网络通了,端口没人应答——包到了,门没人开。
    • 要么服务没起,要么没就绪(第 7 关那个坑),要么端口写错了。

第 2 层和第 3 层,看报错就能分:

  • Connection refused → 到了,门没人开(第 3 层)。
  • Connection timed out → 包根本没到(第 2 层)。

这跟第 1 关那条「客户端连不上服务端」和「服务端上没东西」是同一个思路——先确定断在哪一段,再往下查。

别背具体地址。 解析出的 IP、resolv.conf 里的值,会随环境和 Docker 版本变(第 5 关也说过)。排查时只看 「这个地址是不是我要的那个」。

12.5 两个现成的例子

例一:起不来——端口被占用

报 bind: address already in use。谁占了?在宿主机上跑(不是进容器里):

结果随平台不同:

  • macOS:往往是 com.docker.backend——另一个容器已经把这个端口发布出去了(第 5 关)。
  • Linux:通常是 docker-proxy,也可能是任意一个在用 8080 的进程。
  • Windows:用 netstat -ano | findstr :8080(最后一列是 PID),再 tasklist /FI "PID eq " 看是哪个程序。

例二:连不上——mysql 还没就绪

第 2 关那个坑:mysql 第一次启动要先初始化十几秒,这期间连 3306 会被拒。不是密码错,也不是网络错。

还在初始化,就等;打印出 ready for connections,再连。要自动等,第 7 关的 healthcheck 是正解。

12.6 顺序

十分钟排查,照这个顺序走:

  1. docker ps -a——活着还是死了,退出码多少。
  2. docker logs——它自己说了什么。
  3. docker inspect——配置对不对(命令、环境变量、挂载、端口、网络)。
  4. docker exec 进去——网络三层逐层验。

跟第 8 关的分界:第 8 关讲信号为什么传不到主进程(进程语义),本关讲出了事按什么顺序查(排查动作)。两关都会碰到「容器莫名其妙退出」,但一个解释原因,一个定位位置。

这一关的产出:一套从「死没死」到「哪一层」的排查顺序。下一关换到安全——同样的容器,怎么让它即使出错,也伤不到外面。

本关命令速查

容器状态与排查,见 命令速查表 · 容器生命周期、命令速查表 · 镜像。

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论