K8s 排障:那次让我记忆犹新的 Pod CrashLoopBackOff
一、凌晨两点的告警
那是去年双十一大促前的压测夜。凌晨两点,手机响了——Prometheus 告警:订单服务的 Pod 连续重启,状态 CrashLoopBackOff。
我迷迷糊糊打开电脑,看到 6 个 Pod 里有 4 个在不断重启。每次起来撑 30 秒,然后被 kill,再起来,再 kill。K8s 的重启退避机制已经生效,间隔从 10 秒拉长到 5 分钟。
线上压测环境,离大促只剩三天。
二、第一层排查:看日志
老规矩,kubectl logs <pod> --previous。
日志只有三行:
2026-11-08 02:03:11 INFO Starting OrderServiceApplication...
2026-11-08 02:03:12 INFO Loading application configuration...
2026-11-08 02:03:13 ERROR Failed to initialize DataSource
然后是堆栈,核心一行:
Caused by: java.net.ConnectException: Connection refused (Address: mysql-order.default.svc.cluster.local:3306)
数据库连接不上。
三、第二层排查:网络通不通
kubectl exec -it <pod> -- nc -zv mysql-order.default.svc.cluster.local 3306
不通。
但 MySQL Pod 明明在跑啊?kubectl get pods 显示 mysql-order-0 是 Running 状态。
试试直接连 IP:kubectl exec -it <pod> -- nc -zv 10.0.3.47 3306——通了。
所以问题在 DNS 解析。
四、第三层排查:CoreDNS 怎么了
kubectl get pods -n kube-system | grep dns
输出让我心里一沉:
coredns-7f9c4b9d6c-2xqk8 0/1 Running 0 3m
coredns-7f9c4b9d6c-8mnbv 1/1 Running 0 3m
coredns-7f9c4b9d6c-pqrst 0/1 Running 0 3m
3 个 CoreDNS Pod,2 个不健康。
kubectl logs coredns-7f9c4b9d6c-2xqk8 -n kube-system 里反复出现:
[ERROR] plugin/errors: 2 mysql-order.default.svc.cluster.local. A: read udp 10.244.2.15:54321->10.0.0.2:53: i/o timeout
CoreDNS 上游 DNS 超时。
五、根因浮出水面
我们集群的 CoreDNS 配置了 forward . /etc/resolv.conf,而节点的 /etc/resolv.conf 里配的是公司内网 DNS 10.0.0.2。
压测期间,大量新 Pod 启动,每个都要做 DNS 解析。内网 DNS 扛不住了——不是完全挂,是间歇性超时。CoreDNS 把集群内域名解析也转发上去了(配置缺陷),导致内部服务发现跟着一起挂。
链路是这样的:
Pod 启动 → 解析 mysql-order.default.svc.cluster.local
→ CoreDNS 收到请求
→ 按配置 forward 到 10.0.0.2(内网 DNS)
→ 内网 DNS 超时
→ Pod 拿不到 DB 地址 → 启动失败 → CrashLoopBackOff
六、止血与修复
止血(5 分钟):
给 CoreDNS 加 rewrite 规则,集群内域名直接走 K8s API,不转发:
.:53 {
errors
health
rewrite continue {
name regex (.*)\.default\.svc\.cluster\.local {1}.default.svc.cluster.local
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
}
重启 CoreDNS,订单 Pod 陆续恢复。
根治(后续):
- CoreDNS 配置改为:集群内域名走
kubernetes插件,外部域名才forward - 内网 DNS 扩容 + 加本地
cache插件 - 加 CoreDNS 监控:解析延迟、转发失败率、缓存命中率
七、这次故障教会我的几件事
1. CrashLoopBackOff 不可怕,可怕的是只看 Pod 不看链路
Pod 重启只是症状。根因可能在网络、DNS、存储、配置任何一个环节。排障要从 Pod 往外一层层剥,而不是盯着 Pod 本身。
2. CoreDNS 是集群的"隐形心脏"
它不出问题时没人注意,一出问题是全集群级联故障。值得单独做监控、做压测、做配置审计。
3. 排障顺序要形成肌肉记忆
我的固定流程:
Pod 状态 → 容器日志 → 事件(Event) → 网络连通性 → DNS → 依赖服务 → 资源配额
每次都按这个顺序走,不会漏。
4. 压测不只是压应用,要压基础设施
那次如果提前对 CoreDNS 做过 DNS 压力测试,根本不会等到凌晨两点才暴露。
八、一个排障速查表(建议收藏)
|
症状 |
第一检查点 |
常用命令 |
|---|---|---|
|
CrashLoopBackOff |
容器日志 |
|
|
ImagePullBackOff |
镜像仓库 |
|
|
Pending |
资源/调度 |
|
|
OOMKilled |
内存限制 |
`kubectl get pod <pod> -o yaml |
|
DNS 解析失败 |
CoreDNS |
|
|
服务不通 |
网络策略/Service |
|
九、写在最后
那次故障之后,我把整个排障过程写成了一页 A4 纸的"K8s 排障决策树",贴在工位上。后来团队里新来的人遇到类似问题,照着走一遍基本都能定位。
排障能力不是天生的,是一次次被坑出来的。 每踩一个坑,就把它变成团队的"免疫记忆"——这才是 SRE 文化的核心。
下次再聊一个更隐蔽的:那次 Pod Running 但 Ready 为 0 的 readiness probe 配置翻车现场。想看的扣 1。
- 点赞
- 收藏
- 关注作者
评论(0)