升级kubeadm集群

众所周知,Kubernetes每隔3个月就会发布一个版本,虽然在2021年7月20日Kubernetes官博宣布,将版本发布周期由每年4次调整为每年3次,但每年3个版本的发布同样意味着更多功能特性的来临,如果一直不更新,势必会导致许多新功能无法使用。因此,如何对Kubernetes集群进行升级是每个Kubernetes用户均需面临的一个问题。目前比较流行的Kubernetes集群部署方式分为kubeadm部署二进制部署,本文主要介绍如何将kubeadm方式部署的Kubernetes集群进行升级。(以1.20.X升级至1.21.X为例)

升级工作基本流程


  1. 升级主控制平面节点(Master节点)
  2. 升级其他控制平面节点(Master节点)
  3. 升级工作节点(Node节点)

准备工作


  • 务必仔细认真阅读目标版本的发行说明Kubernetes各组件之间支持的最大版本偏差说明
  • 应确认集群是由kubeadm创建,确认使用的是静态etcd Pod或者外部etcd,并做好etcd数据备份
  • 务必备份所有重要组件,例如存储在数据库中的应用程序的数据。kubeadm upgrade理论上不会影响你的工作负载,只会涉及Kubernetes内部组件,但备份终究是好的
  • 所有节点必须禁用交换分区

注意事项


  • 在对kubelet进行版本升级之前,需要腾空节点。对于控制节点,其上可能运行着CoreDNS Pods或者其它非常重要的负载
  • 升级kubelet之后,因为容器的Hash值发生变化,所有容器都被重新启动

确定要升级到哪个版本


使用操作系统的包管理器找到最新的1.21稳定版本

1
2
3
4
yum list --showduplicates kubeadm --disableexcludes=kubernetes

# 在列表中查找最新的1.21版本
# 它看起来应该是1.21.X-0,其中X是最新的补丁版本

升级Master节点


说明
Master节点上的升级过程应该每次处理一个节点。首先选择一个要先升级的Master节点。该节点上必须有/etc/kubernetes/admin.conf文件

升级第一个Master节点

升级kubeadm

1
2
# 用最新的补丁版本号替换 1.21.X-0 中的X
yum install -y kubeadm-1.21.X-0 --disableexcludes=kubernetes

待安装成功,验证kubeadm版本正确

1
kubeadm version

驱逐节点

通过将节点标记为不可调度并驱逐节点为节点升级做准备

1
2
# 将 <node-to-drain> 替换为要驱逐的Master节点名称
kubectl drain <node-to-drain> --ignore-daemonsets --delete-emptydir-data

验证升级计划

1
kubeadm upgrade plan

此命令检查集群是否可以升级,并取回要升级的目标版本。命令也会显示一个包含组件配置版本状态的表格

执行升级

选择要升级到的目标版本,运行对应的命令

1
2
# 将X替换为此次升级所选择的补丁版本号
kubeadm upgrade apply v1.21.x

一旦该命令结束,正常升级完成应该会看到如下输出:

1
2
3
[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.21.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

升级kubelet和kubectl

1
2
# 用最新的补丁版本号替换 1.21.X-0 中的X
yum install -y kubelet-1.21.X-0 kubectl-1.21.X-0 --disableexcludes=kubernetes

重启kubelet

1
2
systemctl daemon-reload
systemctl restart kubelet

取消不可调取

将Master节点标记为可调度,让其重新上线

1
2
# 将 <node-to-drain> 替换为节点名称
kubectl uncordon <node-to-drain>

逐台升级其他Master节点

升级kubeadm

1
2
# 用最新的补丁版本号替换 1.21.X-0 中的X
yum install -y kubeadm-1.21.X-0 --disableexcludes=kubernetes

待安装成功,验证kubeadm版本正确

1
kubeadm version

驱逐节点

通过将节点标记为不可调度并驱逐节点为节点升级做准备

1
2
# 将 <node-to-drain> 替换为要驱逐的Master节点名称
kubectl drain <node-to-drain> --ignore-daemonsets --delete-emptydir-data

执行升级

说明
对于其他Master节点不需要执行kubeadm upgrade plan,升级使用kubeadm upgrade node而不是kubeadm upgrade apply

1
kubeadm upgrade node

一旦该命令结束,正常升级完成应该会看到如下输出:

1
2
3
4
[upgrade] The control plane instance for this node was successfully updated!
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[upgrade] The configuration for this node was successfully updated!
[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.

升级kubelet和kubectl

升级kubelet和kubectl

1
2
# 用最新的补丁版本号替换 1.21.X-0 中的X
yum install -y kubelet-1.21.X-0 kubectl-1.21.X-0 --disableexcludes=kubernetes

重启kubelet

1
2
systemctl daemon-reload
systemctl restart kubelet

取消不可调取

将Master节点标记为可调度,让其重新上线

1
2
# 将 <node-to-drain> 替换为节点名称
kubectl uncordon <node-to-drain>

升级Node节点


说明
Node节点上的升级过程应该一次执行一个节点,或者一次执行几个节点,以不影响运行工作负载所需的最小容量。

升级kubeadm

1
2
# 用最新的补丁版本号替换 1.21.X-0 中的X
yum install -y kubeadm-1.21.X-0 --disableexcludes=kubernetes

待安装成功,验证kubeadm版本正确

1
kubeadm version

驱逐节点

通过将节点标记为不可调度并驱逐节点为节点升级做准备

1
2
# 将 <node-to-drain> 替换为要驱逐的Node节点名称
kubectl drain <node-to-drain> --ignore-daemonsets --delete-emptydir-data

执行升级

1
kubeadm upgrade node

一旦该命令结束,正常升级完成应该会看到如下输出:

1
2
3
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[upgrade] The configuration for this node was successfully updated!
[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.

升级kubelet和kubectl

升级kubelet和kubectl

1
2
# 用最新的补丁版本号替换 1.21.X-0 中的X
yum install -y kubelet-1.21.X-0 kubectl-1.21.X-0 --disableexcludes=kubernetes

重启kubelet

1
2
systemctl daemon-reload
systemctl restart kubelet

取消不可调取

将Node节点标记为可调度,让其重新上线

1
2
# 将 <node-to-drain> 替换为节点名称
kubectl uncordon <node-to-drain>

验证集群状态


所有节点升级完成后,在其中一台Master节点执行以下命令,验证所有节点是否再次可用

1
kubectl get node

STATUS应显示所有节点为Ready状态,并且版本号已经被更新

从故障状态恢复


如果执行kubeadm upgrade升级失败并且没有回滚,例如由于执行期间节点意外宕机,可以选择再次运行kubeadm upgrade。此命令是幂等的,并最终确保实际状态是声明的期望状态。要从故障状态恢复,还可以运行kubeadm upgrade apply --forece而无需更改集群正在运行的版本。

在升级期间,kubeadm会向/etc/kubernetes/tmp目录下的如下两个备份目录中写入相关备份数据:

  • kubeadm-backup-etcd-<date>-<time>
  • kubeadm-backup-manifests-<date>-<time>

kubeadm-backup-etcd包含当前Master节点本地etcd成员数据的备份。如果etcd升级失败并且自动回滚也无法修复,则可以将此目录中的内容复制到/var/lib/etcd/进行手工修复。如果使用的是外部etcd,则此备份目录为空。

kubeadm-backup-manifests包含当前Master节点的静态Pod清单文件的备份版本。如果升级失败并且无法自动回滚,则此目录中的内容复制到/etc/kubernetes/manifests目录实现手工恢复。如果由于某些原因,在升级前后某个组件的清单未发生变化,则kubeadm也不会为止生成备份版本。

工作原理


kubeadm upgrade apply在第一个Master节点上执行了以下操作:

  • 检查集群是否处于可升级状态
  • API服务器是可访问的
  • 所有节点处于Ready状态
  • 控制平面是健康的
  • 强制执行版本偏差策略
  • 确保控制面的镜像是可用的或者是可拉取到服务器上的
  • 如果组件配置需要版本升级,则生成替代配置与或使用用户提供的覆盖版本进行配置
  • 升级控制面组件或回滚(如果其中任何一个组件无法启动)
  • 应用新的CoreDNSkube-proxy清单,并强制创建所有必需的RBAC规则
  • 如果旧的证书文件在180后过期,将创建API服务器的新证书和密钥文件并备份旧文件

kubeadm upgrade node在其他Master节点上执行了以下操作:

  • 从集群中获取kubeadm ClusterConfiguration
  • 备份kube-apiserver证书(可选)
  • 升级控制平面组件的静态Pod清单
  • 为本节点升级kubelet配置

kubeadm upgrade node在Node节点上执行了以下操作:

  • 从集群中获取kubeadm ClusterConfiguration
  • 为本节点升级kubelet配置