Kubernetes 集群版本升级方案梳理

This article is extracted from the chat log with AI. Please identify it with caution.

说明:本文由 Codex 根据作者提供的主题、素材与公开资料辅助生成,属于 AI 生成/整理内容,非作者原创。请读者自行甄别并交叉验证。

升级不是一个命令#

Kubernetes 集群升级不是简单执行一条命令。

它至少涉及:

  • 控制平面组件。
  • kubelet。
  • kube-proxy。
  • CNI 插件。
  • CSI 插件。
  • CoreDNS。
  • Ingress Controller。
  • Metrics、日志、监控组件。
  • API 版本兼容性。
  • 应用 Pod 的驱逐和恢复。

所以更准确的说法是:

Kubernetes 升级是一组有顺序、有兼容性约束、有回滚预案的维护动作。

升级方式分类#

托管 Kubernetes#

例如云厂商托管集群。

通常控制平面由云厂商升级,节点池由用户选择时间升级。

优点:

  • 控制平面升级复杂度低。
  • 云厂商会处理一部分兼容性细节。
  • 节点池可以分批滚动。

仍然需要关注:

  • 节点池版本。
  • CNI/CSI/Ingress 插件兼容性。
  • API 废弃和移除。
  • 应用是否能承受 Pod 驱逐。
  • PDB 和可用容量是否足够。

kubeadm 集群#

kubeadm 是自建集群常见方式。

官方升级流程大体是:

升级第一个控制平面节点;
升级其他控制平面节点;
升级工作节点。

每个节点通常都要经历:

升级 kubeadm;
检查升级计划;
执行 kubeadm upgrade;
drain 节点;
升级 kubelet / kubectl;
重启 kubelet;
uncordon 节点;
验证状态。

手工二进制或自定义部署#

如果控制平面和节点组件是手工部署的,升级步骤取决于部署方式。

原则仍然一样:

  • 先看版本偏差策略。
  • 先升控制平面。
  • 再升节点组件。
  • 每一步都要验证。
  • 不跳过 minor 版本。

版本偏差约束#

升级前先看 Kubernetes Version Skew Policy。

几个核心规则:

组件约束
kube-apiserverHA 集群中新旧 apiserver 通常只能相差一个 minor
kubelet不能比 apiserver 新,可以比 apiserver 旧若干 minor,具体看版本策略
kube-proxy不能比 apiserver 新,并且要和本机 kubelet 保持允许范围
kube-controller-manager / kube-scheduler不能比 apiserver 新,通常跟 apiserver minor 对齐
kubectl通常支持和 apiserver 相差一个 minor

升级顺序背后的逻辑是:

先升级 apiserver;
再升级 controller-manager / scheduler;
再升级 kubelet;
最后处理 kube-proxy 等节点侧组件。

不要跳过 minor 版本。

例如:

1.29 -> 1.30 -> 1.31

不要直接:

1.29 -> 1.31

升级前检查清单#

版本和 API#

kubectl version
kubectl get nodes -o wide
kubectl api-resources

重点检查:

  • 当前集群版本。
  • 目标版本。
  • 是否跨 minor。
  • 是否有废弃 API。
  • Webhook 是否支持新版本 API。
  • CRD 是否仍兼容。

可以借助工具扫描废弃 API,例如 Pluto、kubent,或者根据 release notes 自查。

控制面健康#

kubectl get --raw='/readyz?verbose'
kubectl get --raw='/livez?verbose'
kubectl -n kube-system get pods -o wide

对于 kubeadm 集群,还要关注静态 Pod:

ls /etc/kubernetes/manifests
crictl ps | grep kube

etcd 备份#

自建控制平面尤其要备份 etcd。

示例:

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \
  --endpoints=https://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

备份之后最好验证:

ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db

应用可用性#

检查 PodDisruptionBudget:

kubectl get pdb -A

检查是否有单副本关键服务:

kubectl get deploy,statefulset -A

检查节点容量:

kubectl top node
kubectl describe node <node-name>

如果节点一 drain 就导致服务不可用,说明升级方案还没准备好。

kubeadm 升级流程#

下面是一个通用流程,具体版本号要按目标版本替换。

1. 查看目标 patch 版本#

Ubuntu / Debian:

sudo apt update
sudo apt-cache madison kubeadm

RHEL / CentOS / Fedora:

sudo yum list --showduplicates kubeadm --disableexcludes=kubernetes

目标应该选择当前 minor 或目标 minor 的最新 patch。

2. 升级第一个控制平面节点的 kubeadm#

sudo apt-mark unhold kubeadm
sudo apt-get update
sudo apt-get install -y kubeadm='1.<target>.x-*'
sudo apt-mark hold kubeadm

确认版本:

kubeadm version

3. 查看升级计划#

sudo kubeadm upgrade plan

这个命令会检查当前集群是否可以升级,并展示可升级版本和组件配置状态。

4. 执行第一个控制平面节点升级#

sudo kubeadm upgrade apply v1.<target>.x

执行完成后,控制平面静态 Pod 会被更新。

如果是 HA 控制平面,不要同时升级多个控制平面节点。一个节点完成并验证后,再处理下一个。

5. 升级其他控制平面节点#

其他控制平面节点使用:

sudo kubeadm upgrade node

而不是再次执行 kubeadm upgrade apply

6. drain 节点#

升级 kubelet 前,先把节点上的普通工作负载驱逐出去:

kubectl drain <node-name> --ignore-daemonsets

如果有本地临时数据或特殊工作负载,可能还需要额外参数,但不要机械地把 --force--delete-emptydir-data 当成默认选项。

7. 升级 kubelet 和 kubectl#

sudo apt-mark unhold kubelet kubectl
sudo apt-get update
sudo apt-get install -y kubelet='1.<target>.x-*' kubectl='1.<target>.x-*'
sudo apt-mark hold kubelet kubectl

重启 kubelet:

sudo systemctl daemon-reload
sudo systemctl restart kubelet

8. uncordon 节点#

kubectl uncordon <node-name>

确认节点恢复:

kubectl get nodes -o wide
kubectl get pods -A -o wide

9. 升级工作节点#

工作节点可以一个一个升级,也可以按批次升级,但要保证剩余容量足够支撑业务。

通用顺序:

drain node
upgrade kubeadm
kubeadm upgrade node
upgrade kubelet / kubectl
restart kubelet
uncordon node
verify workloads

CNI、CSI 和插件#

kubeadm 升级不会替你完整处理所有插件。

至少要单独确认:

  • CNI 插件是否支持目标 Kubernetes 版本。
  • CSI driver 是否支持目标 Kubernetes 版本。
  • Ingress Controller 是否兼容。
  • Metrics Server 是否兼容。
  • CoreDNS 是否升级成功。
  • kube-proxy 是否升级成功。
  • 监控、日志、备份组件是否兼容。

尤其是 CNI 和 CSI,升级顺序要看各自官方文档。

网络和存储插件不兼容,比控制面升级失败更难排查。

升级中的风险点#

API 移除#

Kubernetes 会在新版本移除旧 API。

如果集群里仍有旧版本资源,例如旧 Ingress API、旧 CRD 版本、旧 PodSecurityPolicy 之类,升级后可能出现无法创建、无法更新或控制器异常。

升级前要检查:

kubectl get apiservices
kubectl get crd
kubectl get validatingwebhookconfiguration
kubectl get mutatingwebhookconfiguration

PDB 阻止 drain#

如果 PDB 太严格,kubectl drain 可能无法驱逐 Pod。

这通常不是坏事,它说明升级会影响可用性。

处理方式应该是:

  • 增加副本。
  • 调整 PDB。
  • 分批升级。
  • 预留容量。

不要一上来就强制删除关键 Pod。

单副本有状态服务#

单副本 StatefulSet、数据库、队列等服务需要特别谨慎。

升级前要确认:

  • 是否有备份。
  • 是否允许短暂停机。
  • 是否有主从切换。
  • 是否依赖本地盘。
  • drain 后 Pod 能否在其他节点恢复。

Webhook 影响控制面#

Admission Webhook 如果不可用,可能影响新资源创建或更新。

升级前检查:

kubectl get validatingwebhookconfiguration
kubectl get mutatingwebhookconfiguration

确认 webhook 服务本身高可用,并且支持目标版本 API。

回滚和恢复#

升级前要接受一个现实:

Kubernetes 控制面升级不是普通应用发布,不应该把“回滚”当成主要恢复手段。

更稳妥的是:

  • 升级前备份 etcd。
  • 每一步升级后立即验证。
  • 一次只升级一个控制平面节点。
  • 工作节点分批升级。
  • 出问题先暂停,不继续扩散。

kubeadm 在升级时会在 /etc/kubernetes/tmp 下生成一些备份目录,例如静态 Pod manifest 和本地 etcd 备份。遇到失败时,应该结合官方恢复说明和现场状态处理。

验证清单#

升级后至少检查:

kubectl get nodes -o wide
kubectl get pods -A -o wide
kubectl get events -A --sort-by=.metadata.creationTimestamp
kubectl get --raw='/readyz?verbose'
kubectl get --raw='/livez?verbose'

业务侧检查:

  • 核心服务是否 Ready。
  • Service、Ingress 是否可访问。
  • DNS 是否正常。
  • HPA 是否能读取指标。
  • 日志和监控是否有数据。
  • PVC 是否能正常挂载。
  • CNI 跨节点通信是否正常。

一套保守升级策略#

生产环境可以按这个节奏:

1. 读 release notes 和 version skew policy
2. 检查废弃 API
3. 检查 CNI / CSI / Ingress / 监控组件兼容性
4. 备份 etcd 和关键应用数据
5. 先升级测试集群
6. 生产先升级一个控制平面节点
7. 验证控制平面和插件状态
8. 升级剩余控制平面节点
9. 分批升级 worker 节点
10. 做业务回归和监控观察

这里的重点不是快,而是每一步都能停下来观察。

小结#

Kubernetes 升级的关键是顺序和兼容性。

不跳 minor;
先控制平面,后工作节点;
先 plan,后 apply;
先 drain,后升级 kubelet;
每一步验证;
插件兼容性单独确认。

如果把升级看成“控制面、节点、插件、应用”四层协同,就比只盯着 kubeadm 命令更接近真实生产环境。

参考资料#

本文共 2943 字,创建于 Jun 28, 2026

相关标签: Kubernetes, DevOps, ByAI