集群升级前的核对清单
把生产环境的 Kubernetes 集群大版本升级(例如从 1.28 升级到 1.30),是所有云原生运维团队每年最头疼的硬仗。很多团队以为在测试环境点一下控制台升级成功了就万事大吉,结果一到生产环境升级 API Server 或 Drain 节点时,故障瞬间爆发:有的应用因为调用了已被移除的v1beta1API 直接丢失了控制器,有的节点因为 PodDisruptionBudget (PDB) 设置过于严格导致 Drain 命令无限期卡死,甚至引发集群脑裂。
集群升级绝不是简单的执行kubeadm upgrade apply命令。升级前必须逐项核验 API 弃用契约、PDB 约束死锁,并构建按节点池分流的金丝雀升级与自动止损机制。
弃用 API 扫描:别让废弃 Group/Version 成为线上隐形炸弹
Kubernetes 在版本演进过程中会定期移除老旧的 API 组(如extensions/v1beta1、autoscaling/v2beta2)。如果你的 GitOps 仓库或 Helm Chart 中依然残留着这些 API 声明,一旦 Control Plane 升级到新版本,旧 API 端点被彻底关闭,ArgoCD 或 kubectl 将再也无法解析这些 Manifest,导致应用无法变更或部署直接报错。
升级前的第一项确认,就是利用确定性扫描工具(如 Pluto 或 Kubent)对集群内运行的所有 live 资源以及 GitOps 仓库中的静态 Manifest 进行全量扫描。
PDB 死锁陷阱:为什么kubectl drain永远卡在 99%
第二项极其致命但经常被忽略的确认,是PodDisruptionBudget (PDB) 配置冲突。
运维人员在升级 Node 节点前,必须对 Node 执行kubectl drain --ignore-daemonsets驱逐 Pod。如果某个核心业务仅部署了 2 个 Replicas,但开发团队配置了minAvailable: 2的 PDB 规则,或者配置了maxUnavailable: 0:
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: critical-service-pdb spec: minAvailable: 2 # 致命陷阱:集群中总共只有 2 个 Pod,Drain 时禁止任何 1 个 Pod 离线 selector: matchLabels: app: critical-service在执行 Drain 时,K8s Eviction API 发现驱逐任何一个 Pod 都会破坏 PDB 规则,于是 Drain 命令被无期限阻塞。如果自动化升级脚本没有设置 Timeout,升级进程将卡在半山腰,进而导致后续节点无法继续升级,造成集群状态不一致。
金丝雀节点池升级与 PodReady 自动回滚策略
集群 Node 节点的升级绝对不能“一轰而上”。必须采用金丝雀节点池 (Canary Node Pool)逐批递进的方式进行。
先挑选 1-2 台非核心 Node 作为金丝雀节点,执行 CNI/Kubelet 升级与节点重构。随后引入自动化健康度巡检:如果在金丝雀节点上调度运行的应用连续 10 分钟出现Unhealthy或CrashLoopBackOff,自动化升级控制面必须立即暂停,并将该节点设置为NoSchedule,触发回滚流程。
生产级升级巡检与节点驱逐 Bash 脚本
为了实现上述确认逻辑的自动化,在升压控制脚本中必须包含确定性的预检与安全 Drain 逻辑。以下是生产环境集群升级预检 Bash 脚本示例:
#!/usr/bin/env bash set -euo pipefail TARGET_K8S_VERSION="v1.30.0" LOG_PREFIX="[K8s-Upgrade-Precheck]" echo "${LOG_PREFIX} 1. 正在使用 Pluto 扫描静态 Helm/GitOps 部署清单..." if ! pluto detect-files -d ./deployments --target-versions k8s=${TARGET_K8S_VERSION} | grep -q "No deprecated APIs found"; then echo "${LOG_PREFIX} ERROR: 发现当前部署清单中存在与 ${TARGET_K8S_VERSION} 不兼容的废弃 API,阻断升级!" exit 1 fi echo "${LOG_PREFIX} 2. 正在检查集群内冲突的 PDB 策略..." # 提取 minAvailable 等于 replicas 导致永远无法 Drain 的潜在危险 PDB BLOCKING_PDBS=$(kubectl get pdb -A -o json | jq -r ' .items[] | select(.status.disruptionsAllowed == 0) | "\(.metadata.namespace)/\(.metadata.name)" ') if [ -n "${BLOCKING_PDBS}" ]; then echo "${LOG_PREFIX} WARNING: 以下 PDB 当前允许的中断数为 0 (DisruptionsAllowed=0),Drain 节点时将被卡死:" echo "${BLOCKING_PDBS}" echo "${LOG_PREFIX} 请先修正上述 PDB 的 minAvailable/maxUnavailable 设置后再试。" exit 1 fi echo "${LOG_PREFIX} 3. 正在安全驱逐金丝雀节点 (Canary Node)..." CANARY_NODE="node-prod-canary-01" # 标记节点不可调度 kubectl cordon "${CANARY_NODE}" # 执行带超时保护的 Drain if ! kubectl drain "${CANARY_NODE}" \ --ignore-daemonsets \ --delete-emptydir-data \ --grace-period=30 \ --timeout=300s; then echo "${LOG_PREFIX} ERROR: Node ${CANARY_NODE} Drain 失败,触发超时保护,取消升级!" kubectl uncordon "${CANARY_NODE}" exit 1 fi echo "${LOG_PREFIX} 金丝雀节点预检与驱逐成功,允许进入 Kubelet 升级阶段。"核心升级验证命令汇总
在进行集群大版本升级的前中后各个阶段,运维架构师需要熟练掌握以下 CLI 排障命令:
# 检查 API Server 暴露的废弃 API 审计指标 kubectl get --raw /metrics | grep "apiserver_requested_deprecated_apis" # 查看特定节点的 Pod 驱逐阻止日志 kubectl get events -n default --field-selector reason=FailedToEvictPod # 查看金丝雀节点上的 Kubelet 服务日志 journalctl -u kubelet -n 100 --no-pager | grep -i "error" # 一键解除节点 Cordon 锁定(紧急回滚时使用) kubectl uncordon -l node-role.kubernetes.io/worker=true把 Kubernetes 集群升级看作是一项严密的安全手术。在正式替换二进制组件前,把 API 废弃检测、PDB 死锁拦截和金丝雀自动回滚这三把锁锁紧,才能做到万无一失。