尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

集群升级前的风险核查

集群升级前的风险核查 集群升级前的风险核查节点排空停滞时应先检查 PodDisruptionBudget、不可驱逐工作负载和副本余量。入口类服务还要确认迁移期间是否保有足够副本避免把维护窗口变成单点风险。在 Kubernetes 生产集群大版本升级例如从 1.25 跨版本升级至 1.28实践中常见隐患除了工具或组件报错外还包括平时未显现、升级时触发的配置死锁与废弃 API 盲区。本文复盘生产集群升级中的排障细节并提供升级前前的自动化校验方案。节点驱逐指令下发后 Worker 节点卡在 Drain 状态。运维团队准备升级 Worker 节点的内核与 Kubelet 版本。执行驱逐指令后终端持续输出以下信息node/node-worker-03 cordoned evicting pod ingress-nginx/ingress-nginx-controller-7d9f4b59c-x29fz error when evicting pod ingress-nginx-controller-7d9f4b59c-x29fz (retry it later): Cannot evict pod as it would violate the pods disruption budget. evicting pod ingress-nginx/ingress-nginx-controller-7d9f4b59c-x29fz运维人员通过诊断命令查看 PodDisruptionBudget (PDB) 与节点资源分配kubectl get pdb -A kubectl describe pdb ingress-nginx-pdb -n ingress-nginx kubectl get nodes -o wide --show-labels输出反映出两项配置组合的制约首先为了保证入口网关的高可用前人配置了 PDB 资源ingress-nginx-pdb其中设置了minAvailable: 2。然而当前集群因为资源紧张Ingress controller 恰好只拉起了 2 个 Pod 副本且分布在node-worker-03和node-worker-04上。当试图驱逐node-worker-03上的 Pod 时驱逐控制器Eviction API发现若杀死该 Pod在新的 Pod 成功调度并通过 ReadinessProbe 就绪之前集群里可用 Pod 数量就会降为 1违背了 minAvailable: 2 的强约束于是驱逐 API 拒绝执行操作。此外新的节点已经被打上了NoSchedule污点导致驱逐控制器陷入了无终止条件的死循环。如果使用--force强删 Pod可能会在流量高峰期引发入口网关的瞬间丢包。找出废弃 API 存量资源与 PodDisruptionBudget 盲区。导致升级卡顿的另一个隐患是跨版本升级时被移出支持Deprecated Removed的 API 版本。在 K8s 升级演进中官方会定期移除老旧的 API Group。例如从 1.25 版本开始autoscaling/v2beta1、poddisruptionbudget/v1beta1以及k8s.gcr.io镜像仓库域名均被移出支持。部分团队在使用 Helm 或 kubectl 部署应用时历史上残留了带有旧apiVersion头的 YAML 存根。升级前虽然 Pod 依然可以正常运行但一旦 API Server 升级完成带有旧 API 版本的 Helm Release 在试图执行helm upgrade或回滚时会因为 API 无法识别导致失败。因此在升级之前必须全面扫清集群内部所有的 PDB 逻辑死锁与废弃 API 存根。用 Go 编写集群升级前废弃 API 自动化扫描校验工具。为了避免升级前人工查阅大量 YAML 文件团队使用 Go 语言配合 K8s Discovery Client 编写了一个自动化预检与 PDB 死锁扫描校验工具package main import ( context fmt os path/filepath time metav1 k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/client-go/discovery k8s.io/client-go/kubernetes k8s.io/client-go/tools/clientcmd k8s.io/client-go/util/homedir ) func main() { var kubeconfig string if home : homedir.HomeDir(); home ! { kubeconfig filepath.Join(home, .kube, config) } config, err : clientcmd.BuildConfigFromFlags(, kubeconfig) if err ! nil { fmt.Printf(无法加载 kubeconfig: %v\n, err) os.Exit(1) } clientset, err : kubernetes.NewForConfig(config) if err ! nil { fmt.Printf(创建 ClientSet 失败: %v\n, err) os.Exit(1) } discoveryClient, err : discovery.NewDiscoveryClientForConfig(config) if err ! nil { fmt.Printf(创建 DiscoveryClient 失败: %v\n, err) os.Exit(1) } ctx, cancel : context.WithTimeout(context.Background(), 1*time.Minute) defer cancel() fmt.Println( 1. 扫描集群内部 PodDisruptionBudget (PDB) 死锁隐患 ) pdbs, err : clientset.PolicyV1().PodDisruptionBudgets().List(ctx, metav1.ListOptions{}) if err ! nil { fmt.Printf(获取 PDB 失败: %v\n, err) } else { for _, pdb : range pdbs.Items { // 判别逻辑若 minAvailable 设为了 100% 或与期望 Pod 数相等可能导致 Drain 阻塞 if pdb.Spec.MinAvailable ! nil { fmt.Printf([警告 PDB] 命名空间: %s, 名称: %s, MinAvailable: %s (请核实是否有足够副本用于驱逐)\n, pdb.Namespace, pdb.Name, pdb.Spec.MinAvailable.String()) } } } fmt.Println(\n 2. 检查 API Server 暴露的 API Group 组版本 ) apiGroups, err : discoveryClient.ServerGroups() if err ! nil { fmt.Printf(获取 API 组失败: %v\n, err) os.Exit(1) } deprecatedGroups : map[string]string{ extensions/v1beta1: 已在 1.22 移出支持请迁移至 networking.k8s.io/v1, autoscaling/v2beta1: 已在 1.25 移出支持请迁移至 autoscaling/v2, policy/v1beta1: 已在 1.25 移出支持请迁移至 policy/v1, } for _, group : range apiGroups.Groups { for _, version : range group.Versions { gv : version.GroupVersion if replacement, isDeprecated : deprecatedGroups[gv]; isDeprecated { fmt.Printf([严重警告 废弃 API] 发现存量 API 版本: %s - 解决方案: %s\n, gv, replacement) } } } fmt.Println(\n扫描完成请处理完毕上述风险点后再发起 K8s 控制平面升级。) }这段工具的核心逻辑在于调用 Discovery Client 获取当前 K8s 控制平面注册的 API 组与资源映射比对内嵌的弃用规则库输出集群中的合规性死角。在 PDB 检测模块中工具会列举出所有可能触发Cannot evict pod堵塞的预警配置方便运维在驱逐节点前提前介入调优。演练 Kubernetes 控制平面升级时的检查与保护动作。在扫清配置死角后团队将升级流程标准化为带有检查点的 Shell 执行脚本#!/usr/bin/env bash set -euo pipefail echo 升级前置检查 1: 扫描弃用 API 与 PDB 死锁 go run /opt/tools/k8s_upgrade_checker.go echo 升级前置检查 2: 验证 etcd 数据备份状态 ETCDCTL_API3 etcdctl --endpointshttps://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 \ snapshot save /var/backups/etcd-snapshot-pre-upgrade.db echo 执行控制平面 upgrade plan 评估 kubeadm upgrade plan echo 依次安全驱逐节点流量 (设置超时保护) TARGET_NODEnode-worker-03 kubectl drain ${TARGET_NODE} \ --ignore-daemonsets \ --delete-emptydir-data \ --timeout5m || { echo CRITICAL: Drain node ${TARGET_NODE} timed out! Rolling back cordon... kubectl uncordon ${TARGET_NODE} exit 1 } echo 执行 Kubelet 升级与重启 apt-get update apt-get install -y kubelet1.28.2-00 systemctl restart kubelet kubectl uncordon ${TARGET_NODE} echo Node ${TARGET_NODE} upgraded and uncordoned successfully.升级 Kubernetes 需要严谨的步骤控制。通过在升级前完成废弃 API 的自动化扫描、解除 PDB 死锁限制并在驱逐节点时设置严格的--timeout回退保护机制有助于在大版本升级中保障业务平滑演进。
返回列表