K8s控制平面升级
K8s 的升级只要按标准流程来,完全可以做到零中断升级,用户完全感知不到。
基础逻辑
什么是控制平面?
K8s 的集群分成两部分:
控制平面(Master 节点):可以理解成集群的 “大脑”,负责管整个集群的状态:比如调度 Pod、维护集群配置、提供 API 接口,核心组件有
kube-apiserver、kube-controller-manager、kube-scheduler,还有存数据的 etcd。工作节点(Worker 节点):就是真正跑你业务 Pod 的机器,上面跑
kubelet来管理本地的 Pod。
升级集群的时候,有个固定的顺序:先升级控制平面,再升级工作节点。因为控制平面要向下兼容旧版本的工作节点,保证你升控制平面的时候,旧版本的工作节点还能正常工作,业务不会断。
我们用什么来升级?
这次我们用的是kubeadm——K8s 官方的集群搭建 & 升级工具,大部分人搭集群都是用的它,它会帮你处理所有的配置升级、组件更新,不用你自己一个个改配置、换镜像,非常省心。
而且我们这次是同大版本的补丁升级:从v1.30.0升到v1.30.3,这种补丁版本基本都是修 bug,没有大的功能变更,升级风险非常小,当然这个流程也适用于跨小版本的升级(比如 1.29 升到 1.30)。
完整升级流程
第一步:先确认,我能升到哪个版本?
首先我得先看看,我的包管理器里有哪些可用的 kubeadm 版本,因为我用的是 Ubuntu 系统,用 apt 作为包管理器,所以先执行:
apt list kubeadm -a输出是这样的:
kubeadm/unknown,now 1.30.3-1.1 amd64 [upgradable from: 1.30.0-1.1] kubeadm/unknown 1.30.2-1.1 amd64 kubeadm/unknown 1.30.1-1.1 amd64 kubeadm/unknown 1.30.0-1.1 amd64很清楚,我当前装的是 1.30.0-1.1,最新的补丁版本是 1.30.3-1.1,就它了,这就是我们这次的目标版本。
第二步:给 Master 节点拉个 “警戒线”
升级之前,我得先不让集群把新的 Pod 调度到 Master 节点上 —— 不然我升级到一半,调度器又把一个新的业务 Pod 安排到 Master 上,那我之前的准备不就白做了
执行这个命令:
kubectl cordon cka-master这里的cka-master是我的 Master 节点的名字,cordon这个命令的作用,就是把节点标记为不可调度。
什么意思?就是节点本身还是正常运行的,已经在上面跑的 Pod 也不会动,但是调度器不会再把新的 Pod 往这个节点上放了,相当于给节点拉了个警戒线,只出不进。
执行完我查一下节点状态:
kubectl get nodesNAME STATUS ROLES AGE VERSION cka-master Ready,SchedulingDisabled control-plane 5d6h v1.30.0 cka-worker1 Ready worker 5d6h v1.30.0 cka-worker2 Ready worker 5d5h v1.30.0看到 Master 节点的状态里多了SchedulingDisabled,就说明这步成了。
第三步:把 Master 上的旧 Pod 都挪走
警戒线拉完了,接下来要把 Master 上已经在跑的普通 Pod,都赶到其他工作节点上去 —— 不然我等下重启 kubelet 的时候,这些 Pod 不就被杀了?业务不就断了?
用这个命令排空节点:
kubectl drain cka-master --delete-emptydir-data --ignore-daemonsets这里的两个参数,是你必须要加的:
--ignore-daemonsets:忽略 DaemonSet 类型的 Pod DaemonSet 是什么?就是那种每个节点都必须跑一个的 Pod,比如我们的网络插件 calico,每个节点都得有一个,不然网络就不通了。这种 Pod 你赶不走的,你把它删了,它立刻就会在这个节点上重建一个,所以我们要告诉命令:别管这些 Pod,直接忽略它们。--delete-emptydir-data:删除 Pod 的临时本地数据 有些 Pod 会用emptydir存临时数据,这些数据是跟着 Pod 走的,Pod 挪到别的节点,这些数据就没用了,会在新节点重新生成。不加这个参数的话,drain 会怕你丢数据,不敢删 Pod,直接卡在这里。
加了这两个参数,命令一下就跑通了,它把 Master 上的普通 Pod 一个个驱逐到其他工作节点,整个过程也就十几秒,那些 Pod 在别的节点上重新启动,业务完全没感知。
第四步:升级 kubeadm
Pod 都挪走了,接下来就可以开始升级组件了,首先要升级的就是 kubeadm 本身 —— 毕竟要让新版本的 kubeadm 来帮我们升级集群。
为了防止系统自动升级把 K8s 的版本搞乱,我把kubeadm、kubelet、kubectl这三个包锁定了,也就是apt-mark hold,这样平时执行apt upgrade的时候,就不会不小心把它们升了。
现在要主动升级,所以先把锁解开:
apt-mark unhold kubeadm然后更新包列表,装新版本的 kubeadm:
apt-get update apt install kubeadm=1.30.3-1.1 -y这里一定要指定版本号,不然它会给你装最新的,我们要装我们选好的 1.30.3 版本。
装完我查一下版本,确认没问题:
kubeadm versionkubeadm version: &version.Info{Major:"1", Minor:"30", GitVersion:"v1.30.3", GitCommit:"6f6904f41ac384ec4391224a2df241460", GitTreeState:"clean", BuildDate:"2024-07-16T23:53:15Z", GoVersion:"go1.22.5", Compiler:"gc", Platform:"linux/amd64"}ok,kubeadm 已经是新版本了。
第五步:执行集群控制平面的升级
接下来就是最核心的一步:用 kubeadm 升级整个控制平面。
首先我先做个预检查,看看集群有没有问题,别升一半失败了:
kubeadm upgrade plan这个命令会帮我检查:etcd 是不是健康?各个组件是不是正常?有没有不兼容的配置?全部检查完之后,告诉我可以执行的升级命令。
预检查没问题,就可以执行实际的升级了:
kubeadm upgrade apply v1.30.3 --etcd-upgrade=false这里我加了--etcd-upgrade=false,因为我这次不想升级 etcd,只升其他控制平面组件,如果你想连 etcd 一起升,去掉这个参数就可以,默认是会一起升的。
执行的时候它会问我确认:
[upgrade/version] You have chosen to change the cluster version to "v1.30.3" [upgrade/versions] Cluster version: v1.30.0 [upgrade/versions] kubeadm version: v1.30.3 [upgrade] Are you sure you want to proceed? [y/N]:我输入y确认,然后它就开始逐个升级组件了:
[apiclient] Found 1 Pods for label selector=kube-apiserver [upgrade/staticpods] Component "kube-apiserver" upgraded successfully! [apiclient] Found 1 Pods for label selector=kube-controller-manager [upgrade/staticpods] Component "kube-controller-manager" upgraded successfully! [apiclient] Found 1 Pods for label selector=kube-scheduler [upgrade/staticpods] Component "kube-scheduler" upgraded successfully!它是一个一个升的,升一个的时候,其他的控制平面组件还在正常跑,所以整个过程集群完全可用,业务一点都没断。
全部升完之后,它给我返回了成功的提示:
[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.30.3". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.控制平面的核心组件已经升完了
第六步:升级 kubelet 和 kubectl
核心组件升完了,接下来要把 Master 节点上的kubelet和kubectl也升了,这两个是节点上的代理和命令行工具,也要和控制平面版本一致,不然会有兼容问题。
同样的,先解锁这两个包:
apt-mark unhold kubelet kubectl然后安装新版本:
apt install kubelet=1.30.3-1.1 kubectl=1.30.3-1.1 -y搞定,这两个也升级完成了。
第七步:把 Master 节点恢复正常
所有组件都升完了,现在要做收尾工作,把 Master 节点恢复成正常的状态:
先把三个包重新锁上,防止以后不小心自动升级:
apt-mark hold kubelet kubectl kubeadm重启 kubelet,让新的 kubelet 生效:
systemctl daemon-reload systemctl restart kubelet.service最后,把之前的调度禁止取消,让 Master 节点可以重新接新的 Pod:
kubectl uncordon cka-master
做完这些,我再查一下节点状态:
kubectl get nodesNAME STATUS ROLES AGE VERSION cka-master Ready control-plane 5d7h v1.30.3 cka-worker1 Ready worker 5d6h v1.30.0 cka-worker2 Ready worker 5d6h v1.30.0Master 节点的版本已经变成 1.30.3 了,状态也恢复正常了,整个升级过程就完成了
注意
别直接装包就完事,不排空节点
别忘了锁包版本。
别同时升所有节点
跨版本别跳太多
