Kubernetes集群故障分析与排查手册

一、故障概述

1. 集群基础信息

项目详情
集群架构单Master + 3 Worker节点
集群版本Kubernetes v1.20.8
业务组件KubeSphere v3.2.1、DevOps、监控日志体系、NFS存储、Ingress网关
容器运行时Docker
网络插件Flannel

2. 故障影响范围

  • 控制面故障:Master节点状态丢失,kube-apiserver认证异常,集群管控能力失效
  • 业务影响:KubeSphere控制台无法访问,NodePort端口不通,系统组件与KubeSphere全栈组件批量异常
  • 持续时长:约1.5小时
  • 最终结果:全部组件恢复正常,节点负载均衡分配,集群回归稳定运行状态

二、故障时间线与连锁链路

阶段1:控制面认证失效(触发源)

  1. 前置操作:集群证书续期后重启Master节点
  2. 现象:kubelet持续报错User "system:anonymous" cannot list resource,节点k8s-master无法被识别
  3. 误操作:执行kubectl delete node k8s-master尝试重置节点状态
  4. 后果:Master节点对象从etcd中彻底删除,kubelet客户端证书身份绑定失效,完全无法注册节点

阶段2:Pod批量重调度(连锁故障)

  1. 触发:Master节点NotReady超过容忍时间,K8s驱逐机制启动,全集群Pod触发重调度
  2. 现象:大量系统组件、KubeSphere组件被调度到资源空闲的k8s-node3节点
  3. 隐患:k8s-node3仅运行业务负载,无任何KubeSphere、系统核心组件的本地镜像缓存

阶段3:批量镜像拉取失败(故障爆发)

  1. 现象:全集群18+Pod进入ImagePullBackOff状态,覆盖KubeSphere核心、监控、日志、DevOps、DNS、存储等全链路组件
  2. 直接原因:节点无本地镜像 + 公网Docker Hub/镜像仓库连通性异常,远程拉取全部失败
  3. 叠加问题:部分组件imagePullPolicyAlways,强制远程拉取,即使本地有镜像也无法复用

阶段4:调度冲突与最终修复

  1. 临时方案:强制Pod调度到镜像完整的k8s-node1,快速恢复服务
  2. 衍生问题:有状态组件滚动更新时,受nodeSelector限制新Pod无节点可调度,进入Pending状态
  3. 最终优化:按组件角色分散调度到对应节点,修正镜像拉取策略,清理异常副本,集群全量恢复

三、分层根因分析

1. 控制面认证失效根因

Kubernetes节点身份采用证书绑定机制

  • kubelet客户端证书的CN字段为system:node:<节点名>,与etcd中的节点对象UID强绑定
  • 执行delete node后,节点对象被销毁,原有客户端证书的身份不再被apiserver认可
  • apiserver将无效证书的请求直接降级为匿名用户system:anonymous,无任何集群操作权限,导致节点无法注册、持续报错

2. 批量镜像拉取失败根因

  • 节点镜像分布不均:仅k8s-node1和Master节点有完整的系统+KubeSphere镜像,node2、node3镜像缺失严重
  • 重调度机制触发:Master节点异常后,调度器将大量Pod重新分配到node3,直接命中镜像空白节点
  • 公网拉取能力缺失:集群无法稳定访问公网镜像仓库,远程拉取超时失败,最终进入ImagePullBackOff退避状态

3. Pod调度Pending根因

  • 为修复镜像问题给Deployment添加了nodeSelector强制调度约束
  • 滚动更新时,新Pod与旧Pod需调度到同一节点,但有状态组件(如MinIO)存在存储、端口独占限制,新Pod无法启动
  • Master节点默认带有node-role.kubernetes.io/master:NoSchedule污点,普通Pod无法调度,最终全部节点均不满足调度条件

四、标准化排查流程(同类故障通用)

场景1:节点NotReady / kubelet认证异常

排查步骤(由面到点)

  1. 第一步:确认节点全局状态

    kubectl get nodes
    

    判断是单节点异常还是全集群异常,缩小排查范围。

  2. 第二步:查看kubelet核心日志(定位关键)

    journalctl -u kubelet -f -n 50
    

    关键报错对应根因:

    报错关键字根因
    system:anonymouskubelet客户端证书失效/身份不被认可
    x509: certificate has expired证书已过期
    x509: certificate signed by unknown authorityCA证书不匹配
    node xxx not found节点对象不存在,无法注册
  3. 第三步:核对kubelet配置与证书有效性

    # 查看kubelet配置
    cat /etc/kubernetes/kubelet.conf
    # 验证客户端证书有效期与身份
    openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -text -noout | grep -E "Subject:|Not After"
    

    正常证书Subject应为CN=system:node:<节点名>, O=system:nodes

  4. 第四步:验证apiserver连通性

    curl --cacert /etc/kubernetes/pki/ca.crt https://<master-ip>:6443/version
    

    排除网络、端口、防火墙问题。


场景2:Pod ImagePullBackOff 镜像拉取失败

排查步骤

  1. 第一步:确认Pod调度节点与镜像信息

    kubectl get pod <pod-name> -n <namespace> -o wide
    kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[0].image}'
    

    明确Pod运行在哪个节点、使用的完整镜像名与标签。

  2. 第二步:查看具体拉取报错

    kubectl describe pod <pod-name> -n <namespace> | tail -20
    

    报错对应根因:

    报错关键字根因
    manifest for xxx not found镜像名/标签不存在,拼写错误
    connection refused / timeout镜像仓库网络不通
    no pull access / unauthorized镜像仓库认证失败
  3. 第三步:核对目标节点本地镜像
    登录Pod调度的节点,执行:

    # Docker运行时
    docker images | grep <镜像名>
    # Containerd运行时
    crictl images | grep <镜像名>
    

    必须镜像名、仓库地址、标签完全一致,才会被识别为本地已有镜像。

  4. 第四步:核对镜像拉取策略

    kubectl get deploy <工作负载名> -n <namespace> -o yaml | grep imagePullPolicy
    
    • Always:强制每次拉远程,失败直接报错
    • IfNotPresent:本地有就用本地,没有才拉远程
    • Never:仅用本地镜像,不拉远程

场景3:Pod Pending 调度失败

排查步骤

  1. 第一步:直接查看调度事件(90%问题可直接定位)

    kubectl describe pod <pod-name> -n <namespace> | grep -A 10 Events
    

    事件对应根因:

    事件关键字根因
    node(s) had taint, that the pod didn't tolerate节点有污点,Pod无对应容忍
    node(s) didn't match Pod's node affinity不满足nodeSelector/节点亲和性规则
    Insufficient cpu/memory节点资源不足
    persistentvolumeclaim is already bound存储被旧Pod占用,有状态服务冲突
  2. 第二步:核对节点资源与标签

    # 查看节点可分配资源
    kubectl describe node <节点名> | grep -A 10 Allocatable
    # 查看节点标签
    kubectl get node <节点名> --show-labels
    
  3. 第三步:核对工作负载的调度规则
    检查Deployment/StatefulSet的nodeSelectoraffinitytolerations配置,确认是否存在过度约束。


五、故障修复方案汇总

1. Master节点认证失效修复

应急快速恢复(优先保证集群可用)

直接用管理员配置覆盖kubelet配置,临时获得注册权限:

cp /etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf
chmod 644 /etc/kubernetes/kubelet.conf
systemctl restart kubelet

注意:此为应急方案,kubelet会持有管理员权限,故障恢复后需换回标准配置。

标准合规修复(生产推荐)

用集群CA签发符合节点身份规范的客户端证书,重建kubelet配置:

# 1. 停止kubelet,清理旧证书
systemctl stop kubelet
rm -rf /var/lib/kubelet/pki/kubelet-client-*.pem
mv /etc/kubernetes/kubelet.conf /etc/kubernetes/kubelet.conf.bak

# 2. 生成并签发节点证书
openssl genrsa -out /var/lib/kubelet/pki/kubelet-client.key 2048
openssl req -new -key /var/lib/kubelet/pki/kubelet-client.key \
  -out /var/lib/kubelet/pki/kubelet-client.csr \
  -subj "/CN=system:node:k8s-master/O=system:nodes"
openssl x509 -req -in /var/lib/kubelet/pki/kubelet-client.csr \
  -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key \
  -CAcreateserial -out /var/lib/kubelet/pki/kubelet-client.crt -days 365
cat /var/lib/kubelet/pki/kubelet-client.crt /var/lib/kubelet/pki/kubelet-client.key > /var/lib/kubelet/pki/kubelet-client-current.pem

# 3. 生成标准kubelet配置
kubeadm init phase kubeconfig kubelet
systemctl restart kubelet

2. 批量镜像拉取失败修复

方案A:调度到有镜像节点(快速恢复)

给工作负载添加节点选择器,强制调度到镜像完整的节点:

kubectl patch deploy <工作负载名> -n <命名空间> \
  -p '{"spec":{"template":{"spec":{"nodeSelector":{"kubernetes.io/hostname":"k8s-node1"}}}}}'

删除异常Pod触发重建:

kubectl delete pod <pod-name> -n <命名空间>

方案B:修正镜像拉取策略

将强制拉取改为优先使用本地镜像:

kubectl patch deploy <工作负载名> -n <命名空间> \
  -p '{"spec":{"template":{"spec":{"containers":[{"name":"<容器名>","imagePullPolicy":"IfNotPresent"}]}}}}'

方案C:跨节点同步镜像(彻底解决)

  1. 在有镜像的节点打包镜像
    docker save <镜像1> <镜像2> -o /tmp/images.tar.gz
    
  2. 传输到目标节点
    scp /tmp/images.tar.gz root@<目标节点IP>:/tmp/
    
  3. 目标节点导入镜像
    docker load -i /tmp/images.tar.gz
    

3. Pod调度Pending修复

节点污点导致的无法调度

给Pod添加对应污点容忍,或移除节点污点(不推荐master节点操作):

# 示例:添加master污点容忍
kubectl patch deploy <工作负载名> -n <命名空间> \
  -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"node-role.kubernetes.io/master","effect":"NoSchedule"}]}}}}'

nodeSelector过度约束导致的无法调度

移除节点选择器,恢复默认调度:

kubectl patch deploy <工作负载名> -n <命名空间> \
  --type json -p '[{"op":"remove","path":"/spec/template/spec/nodeSelector"}]'

六、预防与优化建议

1. 操作规范(规避人为故障)

  • 绝对禁止删除单Master集群的控制面节点:节点异常优先排查kubelet、证书、网络,删除节点会触发身份失效、Pod重调度等连锁故障
  • 证书续期后必须做验证:续期完成后检查kubeletapiservercontroller-manager状态,确认节点Ready、组件正常后再重启
  • 集群核心操作前备份:修改证书、节点、调度规则前,备份/etc/kubernetes目录,便于快速回滚

2. 镜像管理(解决拉取失败根因)

  • 核心组件镜像全节点同步:系统组件、KubeSphere组件、存储网关等基础服务的镜像,提前同步到所有Worker节点,避免重调度后无镜像可用
  • 搭建私有镜像仓库(如Harbor):统一管理集群所有镜像,配置镜像缓存,消除对公网仓库的依赖
  • 规范镜像拉取策略:固定版本号的生产镜像统一使用IfNotPresent,仅latest标签的测试环境使用Always

3. 调度优化(均衡负载+高可用)

  • 核心组件分散部署:控制台、监控、日志、网关等组件按角色分配到不同节点,避免单节点压力过载,同时规避单点故障
  • 配置Pod反亲和性:多副本组件添加节点反亲和规则,避免同一服务的多个副本调度到同一节点
  • Master节点隔离:普通业务Pod禁止调度到Master节点,保留资源给控制面组件,避免资源争抢导致集群失控

4. 监控与告警

  • 配置节点状态告警:节点NotReady超过1分钟立即告警
  • 配置Pod异常告警:ImagePullBackOffPendingCrashLoopBackOff状态持续超过5分钟告警
  • 配置证书过期告警:提前30天告警证书过期,避免突发证书失效