Repository Reading Site
故障排查实验室 — 面试最实战的能力
面对任何 K8s 故障,按这个顺序排查: --- 容器进程退出(exit code 非 0)→ kubelet 按 `restartPolicy` 重启 → 又退出 → 退避重启(间隔 10s, 20s, 40s, 80s, 160s, 最大 300s) **常见原因:** 配置错误、依赖服务不可达、缺少环境变量、启动命令错误 **面试答法:** "看 de
故障排查实验室 — 面试最实战的能力
排查方法论
面对任何 K8s 故障,按这个顺序排查:
1. kubectl get pods -o wide → 看状态、哪个节点
2. kubectl describe pod <name> → 看 Events、Conditions
3. kubectl logs <pod> → 看应用日志
4. kubectl logs <pod> --previous → 看上一次崩溃的日志
5. kubectl get events --sort-by=.lastTimestamp → 看集群事件
6. kubectl exec -it <pod> -- sh → 进容器排查
7. kubectl top pods/nodes → 看资源使用
8. journalctl -u kubelet → 看节点级日志
场景 1: CrashLoopBackOff
制造故障
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo starting; exit 1"] # 启动即退出
现象
NAME READY STATUS RESTARTS AGE
crash-demo 0/1 CrashLoopBackOff 1 (10s ago) 16s
排查
# describe 看到:Exit Code: 1,Restart Count 持续增加
kubectl describe pod crash-demo | grep -A5 "Last State"
Last State: Terminated
Reason: Error
Exit Code: 1
# logs 看到应用输出
kubectl logs crash-demo
starting
# --previous 看上一次崩溃的日志(如果容器重启太快来不及看)
kubectl logs crash-demo --previous
原因分析
容器进程退出(exit code 非 0)→ kubelet 按 restartPolicy 重启 → 又退出 → 退避重启(间隔 10s, 20s, 40s, 80s, 160s, 最大 300s)
常见原因: 配置错误、依赖服务不可达、缺少环境变量、启动命令错误
面试答法: "看 describe 的 Exit Code 和 Reason,看 logs 的应用错误信息。Exit Code 137 = OOMKilled,Exit Code 1 = 应用错误,Exit Code 0 但还是 CrashLoop = 主进程退出了(不是长驻进程)。"
场景 2: ImagePullBackOff
制造故障
image: nginx:99.99.99-nonexistent # 不存在的 tag
排查
kubectl describe pod bad-image | grep Events -A5
Warning Failed 10s kubelet Failed to pull image "nginx:99.99.99-nonexistent": not found
常见原因
| Events 信息 | 原因 |
|---|---|
not found |
镜像或 tag 不存在 |
unauthorized |
没有 imagePullSecret |
i/o timeout |
网络不通或 registry 被墙 |
manifest unknown |
tag 存在但平台不匹配(如 arm64 镜像在 amd64 节点) |
场景 3: Pending(资源不足)
制造故障
resources:
requests:
memory: 100Gi # 没有节点有 100G 内存
排查
kubectl describe pod greedy-pod | grep Events -A3
Warning FailedScheduling default-scheduler
0/5 nodes are available:
1 node(s) had untolerated taint {control-plane},
4 Insufficient memory.
关键: Scheduler 的 FailedScheduling 事件会精确告诉你为什么调度不上去。
常见 Pending 原因
| 事件信息 | 原因 | 解决 |
|---|---|---|
| Insufficient cpu/memory | 资源不够 | 降低 requests 或加节点 |
| no nodes match nodeSelector | 没有匹配标签的节点 | 检查标签 |
| untolerated taint | 节点有 taint | 加 toleration |
| PVC not bound | 存储没就绪 | 检查 StorageClass/PV |
场景 4: Service 不通(Endpoints 为空)
制造故障
# Service 的 selector 和 Pod 的 label 不匹配
spec:
selector:
app: WRONG-LABEL # Pod 实际标签是 app: web-test
排查
# 关键:检查 Endpoints
$ kubectl get endpoints broken-svc
NAME ENDPOINTS
broken-svc <none> ← 空!没有后端 Pod
# 对比 selector 和 labels
$ kubectl get svc broken-svc -o jsonpath="{.spec.selector}"
{"app":"WRONG-LABEL"}
$ kubectl get pods --show-labels | grep web-test
web-test-xxx app=web-test ← 不匹配!
面试答法: "Service 不通第一步看 Endpoints。Endpoints 为空说明 selector 没匹配到 Pod。对比 Service 的 selector 和 Pod 的 labels。"
场景 5: Node NotReady
制造故障
ssh root@<node> "systemctl stop kubelet"
现象(约 80 秒后)
hk652699382121 NotReady <none> 3h v1.30.14
排查
kubectl describe node hk652699382121 | grep Conditions -A10
Ready False KubeletNotReady container runtime network not ready
常见原因
| 原因 | 检查方法 |
|---|---|
| kubelet 挂了 | systemctl status kubelet |
| 容器运行时挂了 | systemctl status containerd |
| 磁盘满了 | df -h(kubelet 有磁盘压力阈值) |
| 内存不足 | free -m |
| 网络断了 | ping <master-ip> |
场景 6: OOMKilled
制造故障
resources:
limits:
memory: 10Mi # 给极小的内存
command: ["tail", "/dev/zero"] # 占满内存
排查
kubectl describe pod oom-demo | grep "Last State"
Last State: Terminated
Reason: OOMKilled ← Linux OOM Killer 杀掉了
Exit Code: 137 ← 128 + 9 (SIGKILL)
面试重点: "CPU 超过 limits 会被节流(throttle),进程变慢但不会被杀。Memory 超过 limits 会被 OOMKill,进程直接终止。所以 CPU limits 可以设高一点(允许 burst),Memory limits 要精确。"
场景 7: 滚动更新卡住
制造故障
kubectl set image deployment/nginx nginx=nginx:999-broken
排查
$ kubectl rollout status deployment/nginx --timeout=3s
Waiting for deployment rollout to finish: 1 out of 3 new replicas have been updated...
error: timed out
$ kubectl get pods -l app=nginx
nginx-7b97df8d44-xxx nginx:1.25 Running true ← 旧 Pod 还在
nginx-dcd499979-xxx nginx:999-broken Pending false ← 新 Pod 起不来
解决
kubectl rollout undo deployment/nginx # 秒级回滚
原理: maxUnavailable=25% 保证至少 75% 的 Pod 保持运行。新 Pod 起不来时,旧 Pod 不会被杀,业务不中断。这就是滚动更新的安全网。
排查必备命令速查
# Pod 级别
kubectl get pods -o wide # 状态、节点、IP
kubectl describe pod <name> # 事件、条件
kubectl logs <pod> [-c container] [--previous] # 日志
kubectl exec -it <pod> -- sh # 进容器
kubectl top pods # CPU/内存
# 节点级别
kubectl get nodes # 状态
kubectl describe node <name> # 条件、资源
kubectl top nodes # 资源使用
kubectl drain <node> --ignore-daemonsets # 维护排空
# 集群级别
kubectl get events --sort-by=.lastTimestamp -A # 全局事件
kubectl get componentstatuses # 控制面状态
# 网络排查
kubectl get endpoints <svc> # Service 后端
kubectl exec <pod> -- nslookup <svc> # DNS
kubectl exec <pod> -- curl <url> # 连通性
# 节点上(SSH 进去)
journalctl -u kubelet -f # kubelet 日志
crictl ps -a # 容器状态
crictl logs <container-id> # 容器日志