15.2. 排错手册

排错不是「猜一个原因然后重启」。先确定故障边界,再收集证据,最后验证假设。这份手册给你一套可以重复执行的流程,以及一张按现象索引的故障表。

层级:

L5 · 参考

难度:

进阶

用途:

故障处理

前置:

核心对象、网络、存储

15.2.1. 五步排错法

架构图

图:不要跳过「确定边界」。同一个 502,可能是 Pod、Service、Ingress、CNI 或外部 LB 的问题。

  1. 定义现象:谁访问谁、什么时间、错误码/超时、影响范围。

  2. 确定边界:单个 Pod?单个节点?单个 namespace?全部服务?

  3. 收集证据:get、describe、logs、events、top、节点日志。

  4. 提出假设:一次只验证一个,写出「如果假设成立,应该看到什么」。

  5. 验证并修复:修复后做回归,确认没有引入新问题。

警告

先取证,再重启

kubectl delete pod 会清掉容器日志与上一次退出状态。先执行 kubectl logs --previous、describe、保存事件,再考虑重启。

15.2.2. 第一分钟做什么

# 1. 集群是否健康
kubectl get --raw='/readyz?verbose'

# 2. 节点是否 Ready
kubectl get nodes -o wide

# 3. 异常 Pod
kubectl get pods -A --field-selector=status.phase!=Running

# 4. 最近事件
kubectl get events -A --sort-by=.lastTimestamp | tail -30

# 5. 控制平面
kubectl get pods -n kube-system -o wide

如果 API 都连不上,先跳到「控制平面」一节,不要在应用层浪费时间。

15.2.3. 按 Pod 状态索引

15.2.3.1. Pending

Pod 没有被调度到节点。

kubectl describe pod <pod> -n <ns> | sed -n '/Events/,$p'

事件关键词

原因

处理

Insufficient cpu/memory

节点资源不足

降 requests、扩容节点、清理僵尸 Pod

node(s) had untolerated taint

污点未容忍

加 toleration,或调度到其他节点

node affinity/selector

亲和性不满足

检查 nodeSelector、affinity、节点标签

persistentvolumeclaim not found

PVC 不存在

创建 PVC 或修正名字

pod has unbound immediate PVC

PVC 未绑定

describe pvc,检查 StorageClass

exceeded quota

资源配额

调整 ResourceQuota

no nodes available

没有可调度节点

检查节点状态与 cordon

15.2.3.2. ImagePullBackOff / ErrImagePull

kubectl describe pod <pod> -n <ns> | grep -A5 -i 'failed'

原因

验证

处理

镜像名 / tag 错

crictl pull <image>

修正镜像

私有仓库无凭据

imagePullSecrets

创建 docker-registry Secret

仓库不可达

节点上 curl registry

配 mirror / 代理

架构不匹配

docker manifest inspect

用多架构镜像

限流

事件中有 429

配镜像加速或重试

15.2.3.3. CrashLoopBackOff

容器启动后反复退出。

kubectl logs <pod> -n <ns> --previous
kubectl describe pod <pod> -n <ns> | grep -E 'Exit Code|Reason|Last State'

退出码

含义

常见原因

0

正常退出

前台进程结束,容器没有常驻进程

1

应用错误

配置错、依赖不可用、启动异常

127

命令不存在

command 路径错

137

被 SIGKILL / OOM

内存超限、liveness 重启

143

SIGTERM

优雅终止、被删除

15.2.3.4. Running 但 0/1

readiness 探针失败,Pod 不接收流量。

kubectl describe pod <pod> -n <ns> | grep -A10 -i readiness
kubectl exec <pod> -n <ns> -- wget -qO- http://localhost:<port>/<path>
kubectl get endpoints <svc> -n <ns>

常见原因:探针路径/端口错、应用启动慢但 initialDelaySeconds 太短、依赖未就绪、host 头不匹配。

15.2.3.5. Terminating 卡住

kubectl get pod <pod> -n <ns> -o yaml | grep -A3 finalizers
kubectl describe pod <pod> -n <ns>
  • finalizer 未清理:找到对应控制器;

  • 优雅终止超时:terminationGracePeriodSeconds;

  • 节点失联:kubectl delete pod --force --grace-period=0(确认容器已停)。

15.2.4. 按故障域索引

15.2.4.1. Service 访问不通

kubectl get svc <svc> -n <ns> -o yaml
kubectl get endpoints <svc> -n <ns>
kubectl get endpointslice -n <ns> -l kubernetes.io/service-name=<svc>
kubectl get pods -n <ns> --show-labels

检查点

正常

异常处理

selector

与 Pod 标签一致

修正 selector

Endpoints

有 Pod IP

检查 readiness、namespace

targetPort

与容器端口一致

修正端口名/号

NetworkPolicy

允许来源

加放行规则

DNS

nslookup svc.ns 有结果

查 CoreDNS

kube-proxy

Pod Running

查规则 / 日志

15.2.4.2. DNS 解析失败

kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
kubectl run dns --image=busybox:1.36 --rm -it --restart=Never -- \
  nslookup kubernetes.default
  • CoreDNS Pod 是否 Ready;

  • 是否被 NetworkPolicy 阻断 53 端口;

  • /etc/resolv.conf 的 nameserver 是否是 Service CIDR 内的地址;

  • 跨 namespace 是否用了短名。

15.2.4.3. Ingress 502 / 404

kubectl get ingress -n <ns> -o yaml
kubectl get svc -n ingress-nginx
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=100
kubectl get endpoints <backend-svc> -n <ns>
  • 404:host / path 不匹配,或 IngressClass 不对;

  • 502:后端未 Ready、端口错、协议错(HTTPS 后端需注解);

  • 504:后端超时,检查 proxy-read-timeout 与应用性能。

15.2.4.4. PVC Pending

kubectl describe pvc <pvc> -n <ns>
kubectl get storageclass
kubectl get pv
kubectl get pods -n kube-system | grep -E 'csi|provisioner'

原因

处理

没有默认 StorageClass

指定 storageClassName 或设默认

WaitForFirstConsumer

先创建使用它的 Pod

容量不足 / 访问模式不匹配

调整请求或 PV

provisioner Pod 异常

查 CSI 日志

拓扑限制

用 allowedTopologies 或本地 PV

15.2.4.5. 节点 NotReady

kubectl describe node <node>
ssh <node> 'systemctl status kubelet; journalctl -u kubelet -n 100 --no-pager'
ssh <node> 'df -h; free -h; systemctl status containerd'

原因

现象

处理

kubelet 挂了

Kubelet stopped posting

重启 kubelet,查配置

磁盘压力

DiskPressure

清理镜像/日志

内存压力

MemoryPressure

驱逐低优先级 Pod

网络插件异常

CNI Pod 未就绪

重启 CNI

证书过期

kubelet 报 x509

轮换证书

时间不同步

TLS 错误

修 NTP

15.2.4.6. 控制平面异常

kubectl get pods -n kube-system
kubectl get --raw='/readyz?verbose'
sudo crictl ps | grep -E 'kube-apiserver|etcd|kube-controller|kube-scheduler'
sudo journalctl -u kubelet -n 200 --no-pager
  • API Server 起不来:看静态 Pod 清单 /etc/kubernetes/manifests/ 与容器日志;

  • etcd 异常:检查磁盘、证书、/var/lib/etcd 空间;

  • 证书过期:kubeadm certs check-expiration;

  • 全部静态 Pod 异常:检查 kubelet 与容器运行时。

15.2.4.7. 资源与性能

kubectl top nodes
kubectl top pods -A --sort-by=cpu
kubectl describe node <node> | sed -n '/Allocated resources/,/Events/p'
kubectl get pod <pod> -o jsonpath='{.status.qosClass}'
  • CPU 高但未限流:看应用本身;

  • CPU 被 throttle:提高 limits 或优化;

  • 内存持续增长:查泄漏,设置合理 limit;

  • 节点磁盘满:清理未使用镜像 crictl rmi --prune。

15.2.5. 常用证据命令

kubectl get events -n <ns> --sort-by=.lastTimestamp
kubectl describe pod <pod> -n <ns>
kubectl logs <pod> -n <ns> --all-containers --tail=200
kubectl logs <pod> -n <ns> --previous
kubectl get pod <pod> -n <ns> -o yaml
kubectl get endpoints,endpointslice -n <ns>
kubectl get pvc -n <ns>
kubectl get --raw='/readyz?verbose'

15.2.6. 不要做的事

  • 不要一上来就删 Pod / 重启节点;

  • 不要同时改多个变量;

  • 不要在没看 Events 的情况下猜镜像问题;

  • 不要把 latest 镜像用于生产;

  • 不要用 --force 删除有状态 Pod 而不确认数据;

  • 不要把「Pod Running」当成「服务可用」。

15.2.7. 延伸阅读