LabHub
学习 学习路径 课程

Kubernetes 运维实务

版本偏差与不停机升级的顺序

在 LabHub 中继续学习

一句话总结

升级不是“安装新版本”,而是“在多个组件的版本差保持于允许范围内的同时,逐级向前移动”。

概念图: 允许组件版本不同的范围 · kube-apiserver · 绝对不能更高 · 只有 kubectl 可以高于 apiserver

为什么需要了解这些

Kubernetes 不是单一程序,而是由 apiserver、controller-manager、scheduler、kubelet、kube-proxy、kubectl 分别作为不同进程运行的分布式系统。不可能同时替换所有组件。如果有 7 个节点,就有 7 个 kubelet;其中一台重启失败时,只有该节点会停留在旧版本。因此,Kubernetes 正式定义了允许组件版本不同的范围,这就是版本偏差策略。

作者扩展家庭实验室的记录中也出现了这个问题。新加入的两台迷你 PC 上残留着旧集群的 v1.32 kubelet,如果直接加入,就会在控制平面与节点版本不一致的状态下运行。最终,作者把从 teardown 开始的清理流程整合成脚本重新执行。版本不是“差不多就行”的数值,而是一项由文档明确规定支持范围的契约。

工作原理

基准始终是 kube-apiserver。其他组件的允许范围都围绕 apiserver 确定。

组件 相对于 apiserver 的允许范围
kubelet 最多可低 3 个次要版本,绝对不能更高
kube-proxy 与 kubelet 规则相同
controller-manager / scheduler 最多可低 1 个次要版本,不能更高
kubectl 上下可相差 1 个次要版本(±1

假设 apiserver 为 1.34。直接套用上表,kubelet 可以是 1.31 到 1.34,controller-manager 最高为 1.34,kubectl 则可以是 1.33 到 1.35。只有 kubectl 可以高于 apiserver,这一点经常令人混淆。

除此之外,还有两条规则。

  1. 次要版本必须逐级升级。 不能从 1.32 直接升级到 1.34,必须经过 1.33。跳过版本后,已存储 API 对象的转换路径不再得到保证。
  2. 不支持控制平面降级。 升级过程中,etcd 中的数据会按新模式写入,因此回退方式不是“降回旧版本”,而是恢复升级前创建的 etcd 快照。这句话将上一模块与本模块连接起来。

kubeadm 集群的实际升级顺序如下。

etcd 스냅샷 백업
  → kubeadm upgrade plan            (무엇이 가능한지 확인)
  → 첫 컨트롤 플레인에서 kubeadm upgrade apply v1.x.y
  → 나머지 컨트롤 플레인에서 kubeadm upgrade node
  → 노드마다: drain → kubelet/kubeadm 패키지 교체 → uncordon

draincordon 的差别也体现在这里。cordon 只阻止之后的调度,已经运行的 Pod 会保持不变。drain 则在此基础上驱逐(evict)现有 Pod。因此,节点维护的标准顺序是:先用 cordon 阻止新工作负载进入,再用 drain 清空节点,完成维护后通过 uncordon 恢复。忘记 uncordon,节点就会悄无声息地闲置。

为了避免驱逐 Pod 时服务中断,可以使用 PodDisruptionBudget。设置 minAvailable: 2 后,只有不会低于该下限的 evict 请求才会获准执行。但 minAvailablemaxUnavailable 只能二选一

生产现场中的常见情况

第一,没有金丝雀就批量升级。 一次升级全部节点后,出现问题时就没有可供对照的旧版本节点。基本做法是先升级一台节点,确认工作负载正常,再分批升级其余节点。如果给节点添加阶段标签,计划就不再只是文档,而会成为集群状态的一部分。

第二,PDB 永久阻塞 drain。 如果副本数为 1,却设置了 minAvailable: 1,这个 Pod 就永远无法被驱逐。drain 停滞数分钟时,应首先检查 PDB。

第三,“状态为 Ready”和“实际能够工作”是两个不同命题。 作者记录过一次经历:部署 KubeVirt 时,所有组件均显示 AllComponentsReady,VM 却无法启动。升级后也是如此。节点 Ready 与工作负载正常必须分别验证。

下一次实验要做什么

对真实节点执行 cordon,将受 PDB 保护的工作负载通过 drain 迁移,再通过 uncordon 恢复节点。以 apiserver 1.34 为基准,亲自填写版本偏差表中的空格;编写从备份到 uncordon 的升级运行手册;并给节点添加阶段标签,用 JSON 制作金丝雀发布计划。