集群升级从来不是一条简单的 kubectl upgrade 命令就能解决的问题。当控制平面版本跨越多个 minor 版本时,API 组的启用状态、默认 admission 行为以及 kubelet 的驱逐逻辑都可能发生隐性变化。在真正动手前,通过 Dry Run 与系统化的影响评估,可以把大部分升级故障消灭在模拟阶段。

Dry Run 的底层机制与正确用法
Dry Run 并不是简单的「打印一下即将执行的命令」。在 Kubernetes 中,kubectl apply --dry-run=server 会将对象发送给 API Server,经过认证、鉴权、准入控制(包括 Mutating 和 Validating Webhook)以及 Schema 校验,只是最后一步「写入 etcd」被跳过。这意味着如果集群启用了自定义准入插件,Dry Run 能真实反映出该插件对新版清单的接受度,而 --dry-run=client 仅做本地 schema 检查,无法发现服务端策略拒绝。
理解这种差异非常关键。很多团队在 CI 里只用 client 模式做预检,结果上线时因为 OPA Gatekeeper 的一条约束规则导致升级后的 DaemonSet 无法创建。正确的做法是在预发环境开启 server 模式,并配合 --server-dry-run 显式声明。下面是一段在 Bash 中批量校验所有命名空间部署的示例:
#!/bin/bash
# 遍历所有命名空间,对存在的 deployment 做 server dry run 校验
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
for d in $(kubectl get deploy -n $ns -o jsonpath='{.items[*].metadata.name}'); do
kubectl get deploy $d -n $ns -o yaml
| kubectl apply --dry-run=server -f - -n $ns
> /dev/null || echo "FAIL: $ns/$d"
done
done
除了 kubectl 自带的参数,集群级升级工具如 kubeadm 也提供了 kubeadm upgrade apply --dry-run。它会模拟下载目标版本镜像、生成新静态 Pod 清单并校验节点可用资源,但不真正替换 /etc/kubernetes/manifests 下的文件。这种方式能提前发现 master 节点磁盘空间不足或镜像仓库不可达的问题,避免升级中途控制平面挂死。
影响评估的三个核心维度
影响评估回答的是「如果升级出事,会炸在哪里」。第一个维度是依赖拓扑。微服务架构下,一个基础组件如 CoreDNS 或 Ingress Controller 的升级失败,会沿着调用链放大到业务层。建议用 kubectl viz 或自建脚本导出 Service 与 EndpointSlice 的映射关系,标记出跨命名空间的关键路径。
第二个维度是容量水位。升级往往伴随节点轮转,若集群本身 CPU 分配率已超过 70%,驱逐 Pod 后很可能无处调度。应通过 Metrics Server 拉取近 7 天峰值数据,计算「单节点下线后剩余可调度量」。第三个维度是业务峰值窗口。电商类业务绝对不能在大促前 48 小时操作,可通过历史 HPA 事件反推安全期。下表列出了常见风险点与评估方式:
| 维度 | 风险表现 | 评估手段 |
|---|---|---|
| 依赖拓扑 | 中间件升级致业务雪崩 | 服务依赖图遍历 |
| 容量水位 | Pod 无法重新调度 | 节点资源余量测算 |
| 业务峰值 | 升级中流量突增 | HPA 历史与日历法 |
将三个维度交叉后,能得到一张升级风险矩阵。例如某集群依赖拓扑复杂但容量充足,则应优先采用「先控制平面、后逐节点蓝绿」的策略;反之容量紧张则必须先把节点扩容再谈升级。这种量化结论比凭经验喊「小心点」有用得多。
把 Dry Run 与影响评估落进自动化流程
人工执行一次评估容易遗漏,真正可持续的方案是把它固化进 GitOps 流水线。每次提交集群版本变更 PR 时,CI 自动拉起一个与生产同构的沙箱集群,跑 server dry run 并比对准入日志差异,同时调用容量评估脚本生成报告评论在 PR 下。这样任何违反策略的字段修改在合并前就被挡住。
具体实现上,可以用 kind 或 vCluster 快速起临时集群,用 helm template 渲染后做 dry run。下面给出一段 GitHub Actions 风格的伪 YAML 逻辑,展示如何串起检查:
# 升级前检查任务(示意)
jobs:
pre_upgrade_check:
runs-on: ubuntu-latest
steps:
- name: 启动沙箱集群
run: kind create cluster --image k8s.gcr.io/kube-apiserver:v1.27.0
- name: 渲染并 dry run
run: |
helm template ./charts | kubectl apply --dry-run=server -f -
- name: 容量评估
run: python3 capacity_eval.py --peak-days 7
当流程跑通后,团队对升级的恐惧感会明显下降。曾经一个客户因手动升级 etcd 版本导致 API 延迟翻倍,引入自动化 dry run 后,类似问题在沙箱中就被准入插件标记为「quota exceeded」。影响评估也不再是文档里的空话,而是每次 PR 都附带的可视化图表。只有把机制工程化,集群升级才能从「运维走钢丝」变成「常规发布」。