Kubernetes 故障排查三板斧:从入门到精通的排障指南
导读:在生产环境中,K8s 集群每天都会面临各种意想不到的问题------Pod 启动失败、服务无法访问、节点状态异常......面对这些问题,运维工程师的排查效率直接决定了业务的恢复速度。本文结合实际生产案例,系统梳理 K8s 故障排查的"三板斧"方法论,帮助你建立一套完整的排障思维框架。
一、为什么 K8s 故障排查这么难?
K8s 作为一个分布式容器编排平台,其架构本身就带来了排查的复杂性:
- 组件繁多:Master 节点涉及 etcd、api-server、scheduler、controller-manager 四大组件;Worker 节点涉及 kubelet、kube-proxy 和 CNI 网络插件;
- 网络分层:物理机网络、Pod 网络、Service 网络三层隔离,任何一层出问题都会导致"不通";
- 抽象层级多:从 Pod 到 Deployment 到 Service 到 Ingress,经过多层代理转发,链路长,定位难。
但万变不离其宗。不管问题表象如何千变万化,K8s 故障排查都有其固定套路。经过大量实践总结,我把排查方法论归纳为 "三板斧":
kubectl describe------ 查事件,看状态kubectl logs------ 看日志,找报错kubectl exec------ 进容器,查细节
下面我们逐一拆解,并结合真实案例进行实战演练。
二、第一斧:kubectl describe ------ 查事件,看状态
2.1 核心原理
kubectl describe 命令可以查看资源的详细元数据 和事件(Events)信息。Events 记录了 K8s 各组件与该资源交互的完整过程,是排查问题的第一入口。
使用场景:
| Pod 状态 | 可能原因 | describe 重点关注 |
|---|---|---|
Pending |
资源不足、节点端口占用、调度失败 | Events 中的 Scheduler 事件 |
ImagePullBackOff |
镜像不存在、镜像仓库权限问题、网络不通 | Events 中的 Pulling/Failed 事件 |
CrashLoopBackOff |
容器启动即退出、端口冲突、配置错误 | Containers 字段的 State 和 Last State |
ErrImagePull |
镜像名称拼写错误、tag 不存在 | Events 中的 Failed to pull image |
RunContainerError |
启动命令不存在、环境变量错误 | Containers 字段的 Message |
2.2 实战案例:镜像拉取失败
问题描述 :部署了一个新业务的 Pod,状态一直显示 ImagePullBackOff。
资源清单:
yaml
apiVersion: v1
kind: Pod
metadata:
name: troubleshooting-describe
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest1111
排查过程:
bash
# 第一步:查看 Pod 状态
[root@master231 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE
troubleshooting-describe 0/1 ImagePullBackOff 0 18s
# 第二步:describe 查看详细信息
[root@master231 ~]# kubectl describe pod troubleshooting-describe
# 重点看 Events 部分
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 69s default-scheduler Successfully assigned ...
Normal Pulling 25s (x3 over 68s) kubelet Pulling image "registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest1111"
Warning Failed 24s (x3 over 68s) kubelet Failed to pull image "...nginx:latest1111": rpc error: code = Unknown desc = Error response from daemon: manifest for ... not found: manifest unknown
Warning Failed 12s (x3 over 67s) kubelet Error: ErrImagePull
Normal BackOff 12s (x3 over 67s) kubelet Back-off pulling image "..."
Warning Failed 12s (x3 over 67s) kubelet Error: ImagePullBackOff
根因分析 :从 Events 中可以清晰看到 manifest unknown,说明镜像 tag latest1111 根本不存在。这就是镜像名称拼写错误导致的。
经验总结 :当看到
ImagePullBackOff状态时,第一时间用describe看 Events,通常 90% 的镜像问题都能在这里定位。
三、第二斧:kubectl logs ------ 看日志,找报错
3.1 核心原理
kubectl logs 用于查看 Pod 中指定容器的标准输出和标准错误日志。当容器已经启动但运行异常时,日志往往是最直接的线索。
常用参数:
bash
# 查看指定容器的日志(Pod 多容器时必须指定 -c)
kubectl logs -c <容器名> <Pod名>
# 查看实时日志(类似 tail -f)
kubectl logs -f <Pod名>
# 查看最近 100 行日志
kubectl logs --tail=100 <Pod名>
# 查看上一次运行的日志(容器重启后查看前一次的日志)
kubectl logs --previous <Pod名>
3.2 实战案例:同 Pod 多容器端口冲突
问题描述 :一个 Pod 中运行了两个 Nginx 容器,状态显示 1/2 Error,不断重启。
资源清单:
yaml
apiVersion: v1
kind: Pod
metadata:
name: troubleshooting-logs
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest
- name: c2
image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
# 此镜像可以正常启动,但是由于都使用80端口,所以会起不来
排查过程:
bash
# 第一步:查看 Pod 状态
[root@master231 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE
troubleshooting-logs 1/2 CrashLoopBackOff 5 (2m10s ago) 5m23s
# 第二步:describe 发现 c2 容器异常退出,但原因不明
[root@master231 ~]# kubectl describe po troubleshooting-logs
# Containers 字段显示:
# c1: State=Running (正常)
# c2: State=Terminated, Reason=Error, Exit Code=1
# Events 只显示 "Back-off restarting failed container",没有更详细信息
# 第三步:用 logs 查看两个容器的日志
[root@master231 ~]# kubectl logs -c c1 troubleshooting-logs
# c1 日志正常:nginx 正常启动
[root@master231 ~]# kubectl logs -c c2 troubleshooting-logs
# c2 日志显示:
2025/12/01 01:11:25 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
...
nginx: [emerg] still could not bind()
根因分析 :K8s 的 Pod 中所有容器共享网络命名空间(Network Namespace) ,这意味着 c1 容器已经占用了 80 端口,c2 容器再尝试绑定 80 端口就会报 Address in use 错误。
经验总结:
describe只能看到容器异常退出,但无法看到退出原因的具体错误信息;- 当
describe的 Events 无法提供足够信息时,一定要用logs查看容器内部日志;- 同一 Pod 中的多容器设计时,务必确保端口不冲突,或者使用不同端口。
四、第三斧:kubectl exec ------ 进容器,查细节
4.1 核心原理
有时候,即使 describe 和 logs 都看了,问题仍然无法定位。这时候就需要进入容器内部进行手动排查,就像登录到一台 Linux 服务器上做故障诊断一样。
常用用法:
bash
# 交互式进入容器(注意指定 -c 参数选择容器)
kubectl exec -it -c <容器名> <Pod名> -- sh
# 非交互式执行命令
kubectl exec -c <容器名> <Pod名> -- ps -ef
# 查看容器内的网络配置
kubectl exec <Pod名> -- ip a
kubectl exec <Pod名> -- cat /etc/resolv.conf
4.2 实战案例:容器启动命令覆盖后的排障
问题描述 :为了排查 c2 容器的问题,我们用 command 和 args 覆盖了容器的默认启动命令,让容器先"活起来",再进去手动操作。
资源清单:
yaml
apiVersion: v1
kind: Pod
metadata:
name: troubleshooting-exec
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest
- name: c2
image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
# 覆盖默认启动命令(相当于 Dockerfile 的 ENTRYPOINT)
command:
- tail
# 覆盖默认参数(相当于 Dockerfile 的 CMD)
args:
- -f
- /etc/hosts
排障过程:
bash
# 第一步:容器成功启动
[root@master231 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE
troubleshooting-exec 2/2 Running 0 3s
# 第二步:进入 c2 容器手动操作
[root@master231 ~]# kubectl exec -c c2 -it troubleshooting-exec -- sh
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 tail -f /etc/hosts
12 root 0:00 sh
# 第三步:尝试手动启动 nginx
/ # nginx
2025/12/01 01:28:52 [emerg] 20#20: bind() to 0.0.0.0:80 failed (98: Address in use)
# 确认是端口冲突!
# 第四步:修改端口后启动
/ # sed -i '/listen/s#80#81#g' /etc/nginx/conf.d/default.conf
/ # nginx
/ # netstat -untalp
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN (c1 容器)
tcp 0 0 0.0.0.0:81 0.0.0.0:* LISTEN (c2 容器,修改端口后成功)
根因分析:通过进入容器手动操作,确认了端口冲突的问题,并找到了修改端口解决冲突的方法。
经验总结:
- 当容器无法正常启动时,可以先临时用
command: [tail, -f, /etc/hosts]让容器保持运行,再exec进去手动排查;command相当于覆盖 Dockerfile 的ENTRYPOINT,args相当于覆盖CMD,这个技巧在故障排查中非常实用;- 进入容器后可以检查配置文件、端口占用、网络连通性等,和操作普通 Linux 系统一样。
五、故障排查决策树
根据实际工作经验,我总结了以下决策树,帮助你快速定位问题:
Pod 异常
├── Pending(无法调度)
│ ├── 节点资源不足 → 扩容节点或清理资源
│ ├── 节点端口被占用 → kubectl describe 确认具体原因
│ └── 调度约束(nodeSelector/污点)→ 检查节点标签和污点配置
│
├── ImagePullBackOff / ErrImagePull(镜像问题)
│ ├── 镜像名称/tag 错误 → describe Events 确认
│ ├── 私有仓库认证失败 → 检查 imagePullSecrets 配置
│ └── 网络不通 → 检查节点到镜像仓库的网络连通性
│
├── CrashLoopBackOff(容器启动即退出)
│ ├── 查看日志 → kubectl logs / kubectl logs --previous
│ ├── 查看退出码 → describe 的 Containers.State.Exit Code
│ │ ├── Exit Code 0 → 正常退出,检查重启策略
│ │ ├── Exit Code 1 → 应用报错,查看日志
│ │ └── Exit Code 137 → OOMKilled(内存不足被杀)
│ └── 进入容器排查 → kubectl exec(配合 command: tail -f ...)
│
├── Running 但服务不可访问
│ ├── Pod 内部 → kubectl exec curl localhost:端口
│ ├── Pod 间通信 → kubectl exec curl 目标Pod_IP:端口
│ ├── Service 代理 → kubectl get svc / kubectl get ep
│ ├── DNS 解析 → kubectl exec nslookup Service名.命名空间.svc.cluster.local
│ └── Ingress → 检查 Ingress 配置和 Ingress Controller 日志
│
└── ContainerCreating(一直卡在创建中)
├── describe 查看 Events
├── 存储卷挂载失败 → 检查 PV/PVC/SC 状态
├── 镜像拉取中 → 检查网络和镜像大小
└── CNI 网络配置失败 → 检查 CNI 插件状态
六、高频故障场景速查表
| 故障场景 | 常见原因 | 排查命令 | 解决方案 |
|---|---|---|---|
Pod 状态 Pending |
节点资源不足 | kubectl describe pod <name> |
扩容节点或清理无用 Pod |
Pod 状态 ImagePullBackOff |
镜像不存在/无权限 | kubectl describe pod <name> |
检查镜像名称、配置 imagePullSecrets |
Pod 状态 CrashLoopBackOff |
应用启动报错/端口冲突 | kubectl logs <name> |
查看日志修复配置,注意同 Pod 端口不冲突 |
Pod 状态 OOMKilled |
内存超限 | kubectl describe pod <name> |
调整 resources.limits.memory |
Pod 状态 RunContainerError |
启动命令不存在 | kubectl describe pod <name> |
检查 command/args 拼写 |
节点状态 NotReady |
kubelet 异常/CNI 故障 | systemctl status kubelet |
检查 kubelet 日志和 CNI 配置 |
| Service 无法访问 | Endpoints 为空 | kubectl get ep <svc名> |
检查 Service selector 与 Pod labels 是否匹配 |
| DNS 解析失败 | CoreDNS 异常 | kubectl exec nslookup xxx |
检查 CoreDNS Pod 状态和配置 |
七、排障思维框架总结
K8s 故障排查的核心思想是自上而下,逐层定位:
用户访问入口
↓
Ingress Controller → Ingress 配置是否正确?
↓
Service → Endpoints 是否有后端 Pod?selector 是否匹配?
↓
Pod → Pod 是否 Running?容器是否 Ready?
↓
容器内部 → 应用是否正常监听端口?日志是否有报错?
↓
节点 → kubelet 是否正常?CNI 网络是否正常?
记住这个排查链路,遇到任何 K8s 问题都能快速定位。
三板斧速记口诀
一 describe 看状态,Events 里找答案;
二 logs 看日志,报错信息最直接;
三 exec 进容器,手动排查不犹豫。
八、写在最后
K8s 故障排查能力的提升,不是靠看文档就能练出来的,核心在于大量的实战练习。建议你:
- 刻意制造故障:手动删除 Pod、修改错误镜像 tag、制造端口冲突等,然后用三板斧排查;
- 记录排障日志:每次排查完问题后,记录问题现象、排查过程、根因分析和解决方案;
- 关注 Events :养成习惯,任何资源出问题第一时间
describe看 Events; - 理解底层原理:了解 Pod 的创建流程、Service 的代理机制、CNI 的网络模型,排查时才能有的放矢。
希望这篇文章能帮助你建立系统的 K8s 故障排查思维,在运维之路上越走越远。
参考资源:
- Kubernetes 官方文档:https://kubernetes.io/zh-cn/docs/
- K8s 故障排查指南:https://kubernetes.io/zh-cn/docs/tasks/debug/
- K8S 版本选择参考:生产环境推荐 1.23.17(最后一个默认支持 Docker 运行时的版本),更高版本需使用 Containerd 运行时。