故障排查

故障排查

故障排查方法论

排查流程

1. 问题识别
   ↓
2. 收集信息(日志、事件、指标)
   ↓
3. 分析根因
   ↓
4. 制定方案
   ↓
5. 实施修复
   ↓
6. 验证结果
   ↓
7. 总结复盘

信息收集工具箱

# 基础信息
kubectl get pods -o wide
kubectl get nodes
kubectl get events --sort-by='.lastTimestamp'

# 详细信息
kubectl describe pod <pod-name>
kubectl describe node <node-name>

# 日志
kubectl logs <pod-name> --tail=100
kubectl logs <pod-name> --previous  # 上一个容器
kubectl logs <pod-name> -c <container>  # 多容器

# 资源使用
kubectl top nodes
kubectl top pods

# 进入容器调试
kubectl exec -it <pod-name> -- /bin/sh

Pod 问题排查

1. Pod 一直处于 Pending

症状:Pod 创建后一直是 Pending 状态

排查步骤

# 查看 Pod 详情
kubectl describe pod <pod-name>

# 常见原因及解决方案

原因 1:资源不足

# 查看事件
Events:
  Warning  FailedScheduling  insufficient cpu

# 解决方案
# 1. 降低资源请求
kubectl edit deployment <name>
# 修改 resources.requests

# 2. 扩容节点
kubectl get nodes
# 添加新节点或扩容现有节点

# 3. 清理不需要的 Pod
kubectl delete pod <unused-pod>

原因 2:镜像拉取失败

# 查看事件
Events:
  Warning  Failed  Failed to pull image "myapp:latest": rpc error

# 检查镜像是否存在
docker pull myapp:latest

# 检查 imagePullSecrets
kubectl get pod <pod-name> -o yaml | grep imagePullSecrets

# 解决方案
# 1. 修正镜像名称
kubectl set image deployment/myapp myapp=correct-image:tag

# 2. 创建镜像拉取凭证
kubectl create secret docker-registry regcred \
  --docker-server=<registry> \
  --docker-username=<username> \
  --docker-password=<password>

# 3. 在 Pod 中引用
kubectl patch deployment myapp -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}}}'

原因 3:节点选择器不匹配

# 查看 Pod 的节点选择器
kubectl get pod <pod-name> -o yaml | grep -A 5 nodeSelector

# 查看节点标签
kubectl get nodes --show-labels

# 解决方案:移除或修改 nodeSelector
kubectl edit deployment <name>

原因 4:PVC 未绑定

# 查看 PVC 状态
kubectl get pvc

NAME      STATUS    VOLUME   CAPACITY
mypvc     Pending   

# 检查 StorageClass
kubectl get storageclass

# 解决方案
# 1. 创建 PV(如果使用静态供应)
# 2. 检查 StorageClass 是否正确
# 3. 查看 PVC 事件
kubectl describe pvc <pvc-name>

2. Pod 频繁重启(CrashLoopBackOff)

症状:Pod 反复重启,状态显示 CrashLoopBackOff

排查步骤

# 查看重启次数
kubectl get pods
NAME     READY   STATUS             RESTARTS   AGE
myapp    0/1     CrashLoopBackOff   5          3m

# 查看日志
kubectl logs <pod-name> --previous

# 查看事件
kubectl describe pod <pod-name>

原因 1:应用启动失败

# 查看应用日志
kubectl logs <pod-name> --previous

# 常见错误
# - 配置文件错误
# - 依赖服务不可用
# - 端口冲突
# - 权限问题

# 解决方案:修复应用代码或配置

原因 2:健康检查失败

# 查看探针配置
kubectl get pod <pod-name> -o yaml | grep -A 10 livenessProbe

# 解决方案
# 1. 调整探针时间
kubectl edit deployment <name>
# 增加 initialDelaySeconds 和 periodSeconds

# 2. 修复健康检查端点
# 确保 /health 或 /readiness 端点正常

# 3. 暂时禁用探针(调试用)
kubectl patch deployment <name> --type=json \
  -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'

原因 3:OOMKilled(内存不足)

# 查看终止原因
kubectl describe pod <pod-name> | grep -A 5 "Last State"

Last State:     Terminated
  Reason:       OOMKilled
  Exit Code:    137

# 查看内存使用
kubectl top pod <pod-name>

# 解决方案
# 1. 增加内存限制
kubectl set resources deployment <name> \
  --limits=memory=2Gi \
  --requests=memory=1Gi

# 2. 优化应用内存使用
# - 检查内存泄漏
# - 优化缓存策略
# - 减少并发处理

原因 4:应用崩溃

# 查看退出码
kubectl describe pod <pod-name> | grep "Exit Code"

# 常见退出码
# 0:   正常退出
# 1:   应用错误
# 137: SIGKILL (OOMKilled)
# 143: SIGTERM (正常终止)

# 调试方法
# 1. 修改命令为 sleep,保持容器运行
kubectl run debug --image=myapp --command -- sleep 3600

# 2. 进入容器手动启动应用
kubectl exec -it debug -- /bin/sh
# 手动运行启动命令,观察错误

3. Pod 处于 ImagePullBackOff

症状:无法拉取镜像

# 完整排查流程
kubectl describe pod <pod-name>

Events:
  Warning  Failed     Failed to pull image "myapp:v1.0": rpc error: code = Unknown
  Warning  BackOff    Back-off pulling image "myapp:v1.0"

# 1. 检查镜像名称是否正确
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].image}'

# 2. 手动拉取镜像测试
docker pull myapp:v1.0

# 3. 检查私有仓库凭证
kubectl get secret
kubectl describe secret <pull-secret>

# 4. 检查网络连接
kubectl run test --image=busybox -it --rm -- wget -O- <registry-url>

# 解决方案
# 方案 1: 修正镜像名称
kubectl set image deployment/myapp myapp=correct-repo/myapp:v1.0

# 方案 2: 使用公共镜像(临时)
kubectl set image deployment/myapp myapp=nginx:latest

# 方案 3: 配置镜像加速
# 在 Docker daemon.json 中配置镜像加速器

4. Pod 状态正常但服务不可访问

排查步骤

# 1. 检查 Pod 是否 Ready
kubectl get pods
NAME     READY   STATUS    RESTARTS
myapp    1/1     Running   0          # ✓ Pod 正常

# 2. 检查容器端口
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].ports}'

# 3. 测试 Pod IP 直接访问
kubectl get pod <pod-name> -o wide
NAME     IP           NODE
myapp    10.244.0.5   node-1

# 进入测试 Pod
kubectl run test --image=busybox -it --rm -- sh
wget -O- http://10.244.0.5:8080

# 4. 检查 Service
kubectl get svc <service-name>
kubectl describe svc <service-name>

# 5. 检查 Endpoints
kubectl get endpoints <service-name>

# 如果 Endpoints 为空,检查标签匹配
kubectl get pod --show-labels
kubectl get svc <service-name> -o yaml | grep selector

# 6. 测试 Service
kubectl run test --image=busybox -it --rm -- sh
wget -O- http://<service-name>:80

# 7. 检查 Ingress
kubectl get ingress
kubectl describe ingress <ingress-name>

网络问题排查

DNS 解析问题

# 测试 DNS
kubectl run test --image=busybox -it --rm -- sh
nslookup kubernetes.default
nslookup <service-name>
nslookup <service-name>.<namespace>.svc.cluster.local

# 检查 CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns

# 检查 DNS 配置
kubectl get configmap coredns -n kube-system -o yaml

# 测试解析
kubectl run dnsutils --image=tutum/dnsutils -it --rm -- sh
dig @10.96.0.10 kubernetes.default.svc.cluster.local

网络连接问题

# 测试 Pod 间网络
kubectl exec <pod-a> -- ping <pod-b-ip>

# 测试跨节点网络
kubectl exec <pod-a> -- ping <pod-on-other-node-ip>

# 检查 NetworkPolicy
kubectl get networkpolicy -A
kubectl describe networkpolicy <name>

# 检查 CNI 插件
kubectl get pods -n kube-system | grep -E 'calico|flannel|weave'

# 查看 iptables 规则(节点上)
sudo iptables-save | grep <service-name>

Service 访问不通

# 完整排查流程

# 1. Service 是否存在
kubectl get svc <service-name>

# 2. Endpoints 是否正常
kubectl get endpoints <service-name>
# 应该有 Pod IP 列表

# 3. Pod 标签是否匹配
kubectl get pods -l <service-selector>

# 4. 测试 ClusterIP
kubectl run test --image=busybox -it --rm -- sh
wget -O- http://<cluster-ip>:<port>

# 5. 检查端口映射
kubectl get svc <service-name> -o yaml
# 查看 port 和 targetPort

# 6. 查看 kube-proxy 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy

性能问题排查

CPU 问题

# 查看 CPU 使用
kubectl top nodes
kubectl top pods --sort-by=cpu

# 查看是否被限流
kubectl describe pod <pod-name> | grep -i cpu

# 检查 CPU 限制
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].resources}'

# 进入容器查看进程
kubectl exec <pod-name> -- top
kubectl exec <pod-name> -- ps aux | sort -rn -k 3 | head -5

# 解决方案
# 1. 增加 CPU 限制
kubectl set resources deployment <name> --limits=cpu=2

# 2. 启用 HPA
kubectl autoscale deployment <name> --cpu-percent=80 --min=2 --max=10

# 3. 优化应用代码

内存问题

# 查看内存使用
kubectl top pods --sort-by=memory

# 查看内存限制
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].resources.limits.memory}'

# 检查是否 OOM
kubectl describe pod <pod-name> | grep OOM

# 进入容器查看内存
kubectl exec <pod-name> -- free -h
kubectl exec <pod-name> -- cat /proc/meminfo

# 分析内存使用(Java 应用)
kubectl exec <pod-name> -- jmap -heap 1

# 解决方案
# 1. 增加内存限制
kubectl set resources deployment <name> --limits=memory=2Gi

# 2. 调整 JVM 参数(Java)
# -Xmx 设置为 limits 的 75%

# 3. 启用内存分析
# 添加 HeapDump 选项

磁盘问题

# 查看节点磁盘使用
kubectl get nodes
kubectl describe node <node-name> | grep -A 5 "Allocated resources"

# 查看 PVC 使用
kubectl get pvc
kubectl exec <pod-name> -- df -h

# 清理镜像(节点上)
ssh node-1
docker system prune -af

# 清理日志(节点上)
find /var/log/containers -name "*.log" -mtime +7 -delete

# 扩容 PVC(如果支持)
kubectl edit pvc <pvc-name>
# 修改 storage 大小

集群级问题

节点 NotReady

# 查看节点状态
kubectl get nodes
NAME     STATUS     ROLES    AGE
node-1   NotReady   worker   10d

# 查看节点详情
kubectl describe node node-1

# 常见原因
# 1. kubelet 未运行
ssh node-1
systemctl status kubelet
systemctl restart kubelet

# 2. 资源耗尽
df -h
free -h

# 3. CNI 插件问题
kubectl logs -n kube-system -l k8s-app=calico-node

# 4. 网络问题
ping <api-server-ip>

API Server 不可访问

# 检查 API Server
kubectl cluster-info

# 检查证书
kubeconfig view
openssl x509 -in ~/.kube/config -text -noout

# 检查 API Server Pod(如果可访问节点)
ssh master-node
docker ps | grep kube-apiserver
docker logs <apiserver-container>

# 查看 API Server 日志
journalctl -u kube-apiserver -f

etcd 问题

# 检查 etcd 状态
ETCDCTL_API=3 etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint health

# 查看 etcd 成员
ETCDCTL_API=3 etcdctl member list

# 备份 etcd
ETCDCTL_API=3 etcdctl snapshot save backup.db

实战案例

案例 1:应用突然无法访问

现象:用户反馈网站无法访问

排查过程

# 1. 检查 Ingress
kubectl get ingress
kubectl describe ingress myapp

# 2. 检查 Service
kubectl get svc myapp
kubectl get endpoints myapp
# 发现 Endpoints 为空!

# 3. 检查 Pod
kubectl get pods -l app=myapp
# 所有 Pod 都是 CrashLoopBackOff

# 4. 查看日志
kubectl logs <pod-name> --previous
# 发现:Error: Cannot connect to database

# 5. 检查数据库
kubectl get pods -l app=mysql
# MySQL Pod 正常

kubectl exec -it <mysql-pod> -- mysql -u root -p
# 无法连接!发现 MySQL 密码被修改

# 6. 根因:Secret 被误修改
kubectl get secret db-secret -o yaml

# 解决:恢复正确的密码
kubectl apply -f backup/db-secret.yaml
kubectl rollout restart deployment myapp

案例 2:Pod 内存持续增长

现象:Pod 定期被 OOMKilled

排查过程

# 1. 确认问题
kubectl get pods
kubectl describe pod <pod-name> | grep OOM

# 2. 查看内存趋势
# 在 Grafana 中查看内存使用曲线
# 发现持续增长,典型的内存泄漏

# 3. 采集堆转储(Java 应用)
kubectl exec <pod-name> -- jmap -dump:live,format=b,file=/tmp/heap.hprof 1
kubectl cp <pod-name>:/tmp/heap.hprof ./heap.hprof

# 4. 分析堆转储
# 使用 Eclipse MAT 或 VisualVM 分析
# 发现:大量未关闭的数据库连接

# 5. 代码修复
# 修复连接池配置,确保连接正确关闭

# 6. 临时缓解
kubectl set resources deployment myapp --limits=memory=4Gi
kubectl autoscale deployment myapp --cpu-percent=50 --min=3 --max=10

案例 3:网络间歇性超时

现象:服务间调用偶尔超时

排查过程

# 1. 查看监控
# Grafana 显示 P99 延迟偶尔飙升

# 2. 检查 Pod 分布
kubectl get pods -o wide
# 发现所有 Pod 都在同一个节点

# 3. 检查节点资源
kubectl top node node-1
# CPU 和内存使用率很高

# 4. 检查其他工作负载
kubectl get pods --all-namespaces -o wide | grep node-1
# 发现有个批处理任务占用大量资源

# 5. 解决方案
# 方案 1: 添加 Pod 反亲和性
kubectl edit deployment myapp
# 添加 podAntiAffinity

# 方案 2: 为批处理任务设置资源限制
kubectl set resources deployment batch-job --limits=cpu=2,memory=4Gi

# 方案 3: 扩容集群
kubectl scale deployment myapp --replicas=6

常用调试工具

kubectl 插件

# 安装 krew(kubectl 插件管理器)
(
  set -x; cd "$(mktemp -d)" &&
  curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_amd64.tar.gz" &&
  tar zxvf krew-linux_amd64.tar.gz &&
  ./krew-linux_amd64 install krew
)

# 有用的插件
kubectl krew install debug          # 调试工具
kubectl krew install tail           # 多 Pod 日志聚合
kubectl krew install tree           # 资源树状视图
kubectl krew install sniff          # 网络抓包

调试容器

# 启动临时调试容器(Ephemeral Container)
kubectl debug -it <pod-name> --image=busybox --target=<container-name>

# 调试节点
kubectl debug node/<node-name> -it --image=ubuntu

# 复制 Pod 进行调试
kubectl debug <pod-name> --copy-to=debug-pod --container=app -- sh

网络抓包

# 使用 ksniff 插件
kubectl sniff <pod-name> -n <namespace>

# 或手动抓包
kubectl exec <pod-name> -- tcpdump -i any -w /tmp/capture.pcap
kubectl cp <pod-name>:/tmp/capture.pcap ./capture.pcap
# 使用 Wireshark 分析

最佳实践

1. 日志规范

  • 使用结构化日志(JSON)
  • 包含关键字段:timestamp、level、message、trace_id
  • 设置合适的日志级别
  • 定期轮转和清理

2. 监控告警

  • 设置关键指标监控
  • 配置合理的告警阈值
  • 建立告警响应流程
  • 定期回顾和优化

3. 故障预防

  • 资源限制必须设置
  • 健康检查必须配置
  • 使用 PDB 防止批量删除
  • 定期备份关键数据

4. 文档记录

  • 记录常见问题和解决方案
  • 建立故障知识库
  • 定期进行故障演练
  • 复盘和改进流程

常用命令速查

# 快速诊断
kubectl get pods --field-selector=status.phase!=Running
kubectl get pods --field-selector=status.phase=Failed
kubectl get events --sort-by='.lastTimestamp' | tail -20

# 资源使用
kubectl top nodes --sort-by=cpu
kubectl top pods --all-namespaces --sort-by=memory

# 批量操作
kubectl delete pods --field-selector=status.phase=Failed
kubectl get pods -o json | jq '.items[] | select(.status.phase != "Running") | .metadata.name'

# 强制删除
kubectl delete pod <pod-name> --grace-period=0 --force

# 查看完整配置
kubectl get pod <pod-name> -o yaml
kubectl get pod <pod-name> -o json | jq

小结

故障排查是 Kubernetes 运维的核心技能:

排查方法

  • 系统化的排查流程
  • 充分收集信息
  • 分析根本原因
  • 验证解决方案

常见问题

  • Pod 问题:Pending、CrashLoop、ImagePull
  • 网络问题:DNS、Service、Ingress
  • 性能问题:CPU、内存、磁盘
  • 集群问题:节点、API Server、etcd

核心工具

  • kubectl describe / logs / exec
  • kubectl top / events
  • kubectl debug
  • 监控和日志系统

关键原则

  • 先看日志和事件
  • 从症状到根因
  • 记录和分享经验
  • 预防胜于治疗

下一章我们将学习安全最佳实践,构建安全的 Kubernetes 环境。