K8s 升级踩坑:kubeadm 从 1.27 到 1.30
K8s 一个季度一个版本,升级是个常态。本文按 kubeadm 跨 3 个版本的实战记录。
跨版本规则
K8s 官方只支持 N→N+1 升级。要跨多版本就要"逐级跳":
1.27 → 1.28 → 1.29 → 1.30
每跳一次必须等集群稳定(一天以上),不能连续跳。
单步升级流程
以 1.27 → 1.28 为例。
1. 升 control plane(第一个 master)
# 1. 升 kubeadm
dnf install -y kubeadm-1.28.0-0 --disableexcludes=kubernetes
# 2. 看升级计划
kubeadm upgrade plan
# 3. 真正升级
kubeadm upgrade apply v1.28.0
# 4. drain 节点
kubectl drain master1 --ignore-daemonsets
# 5. 升 kubelet/kubectl
dnf install -y kubelet-1.28.0-0 kubectl-1.28.0-0
systemctl daemon-reload
systemctl restart kubelet
# 6. uncordon
kubectl uncordon master1
2. 升其他 master
# 在 master2、master3 上
kubeadm upgrade node # 注意是 node 不是 apply
# 然后同上升 kubelet
3. 升 worker
逐个节点:
# 控制面执行
kubectl drain worker1 --ignore-daemonsets --delete-emptydir-data
# 节点上执行
dnf install -y kubeadm-1.28.0-0 kubelet-1.28.0-0
kubeadm upgrade node
systemctl restart kubelet
# 控制面执行
kubectl uncordon worker1
必看 release notes 的坑
跨版本最容易翻车的点:
1.28 砍了
--feature-gates里的 GA feature 不再接受(会报 invalid feature gate)- in-tree GCE/AWS/Azure/vSphere 存储插件全部移到 CSI
1.29 砍了
Secret默认开启 SecretImmutabilityKubeProxyConfigurationv1alpha1 弃用- Pod 安全准入策略对照 v1.29 检查
1.30 砍了
app.kubernetes.io/component一些保留值变化- CRI v1alpha2 完全删除,runtime 必须支持 v1
CNI 兼容性
CNI 插件也要升:
- Calico:跨版本 K8s 升级前先升 Calico 到对应版本
- Cilium:同上
- 自研 CNI:每次升前测一遍
# 查当前 CNI 版本
kubectl get daemonset -n kube-system -l k8s-app=calico-node -o jsonpath='{.items[0].spec.template.spec.containers[0].image}'
回滚
K8s 不支持降级!只能:
- 备份 etcd
- 失败就用 etcd 备份恢复,然后从快照重启
我的升级 checklist
- ☐ 备份 etcd(强制)
- ☐ 看 release notes(关键)
- ☐ staging 演练过(必须)
- ☐ kubelet 配置文件检查兼容性
- ☐ CRI runtime 版本检查
- ☐ 准备 PodDisruptionBudget(drain 才不会断业务)
- ☐ 一台一台升,每台升完观察 10 分钟
教训:跨版本升级出问题最常见的是 webhook(如 cert-manager、ingress-nginx)和 CNI 不兼容,新版本一定先升 webhook 再升 K8s。