亚马逊AWS官方博客

Amazon EKS version 1.21 集群升级实践

Kubernetes 是一个用于实现容器化应用程序的部署、扩展和管理的自动化的开源系统。该软件得到了容器和微服务用户群体的积极认可,并广泛应用于企业的开发,测试和生产应用部署。

Amazon Elastic Kubernetes Service(Amazon EKS)是一项 Kubernetes 容器编排托管服务,在保持与 Kubernetes 开源社区原生兼容的情况下,在底层运行的基础设施方面,提供了一系列的云服务集成和优化增强,帮助用户利用 AWS 基础设施的完整性能、规模、可靠性、可用性和安全性,可以实现自动编排容器、管理应用程序可用性、存储集群数据和管理 Kubernetes 控制面板节点的可用性和可扩展性。让用户轻松应用 Kubernetes 集群,而无需安装、操作或维护自己的控制面板或节点。

与此同时,Kubernetes 社区非常活跃,平均每 4 个月就会发布新的软件版本,在版本迭代过程中,不断带来功能特性的演进、更新和错误修复。Amazon EKS 完全兼容 Kubernetes 社区版本,支持运行上游的 Kubernetes 版本和常见的 Kubernetes 附加模块。致力于保持 EKS 版本更新过程的顺利进行,在任何给定时间都提供四个稳定的 Kubernetes 版本,请查阅当前可用版本版本发布日历。并为每个版本提供 14 个月的生命周期维护和提前 60 天的技术支持终止通知。

但对于运行有生产应用机器的用户,可能依然存在有诸多的软件升级顾虑,包括:

  1. 无法确定和量化 EKS 集群升级所带来的生产应用中断影响。
  2. 无法确认是否能完全复制生产集群的运行环境来验证升级过程。
  3. 无法确认官方提供的软件升级文档是否完全适合自身的集群环境等。

本文以某个物联网企业的 EKS 生产集群为背景,阐述 Amazon EKS 从 1.21 升级到 1.23 的实践过程。在此过程中,融合采用的开源的接口检测工具和 Amazon EKS 技术支持操作手册。希望通过完整的升级过程,缓解或消除用户对 EKS 集群升级的顾虑。

背景说明

某个物联网企业将海外设备管理的生产应用部署在亚马逊云科技海外某区域的 Amazon EKS 集群,采用托管节点组,包含十多个 EC2 节点。集群当前版本 1.21,集群插件包括 CNI plugin,CoreDNS,EBS CSI 和 kube-proxy。遵照 Amazon EKS 的技术支持终止日期通知,计划将 EKS 版本升级到 1.23,后续在基于经验积累,开展常态化版本升级。本期升级通过对比分析 Kubernetes 的版本差异,1.21 到 1.23 之间主要功能差异体现在 API 接口的版本上,需重点关注应用部署接口调用的配置文件。用户较为顾虑配置文件更新的完整性风险。

升级策略

  • 利用第 3 方开源工具 Kubent,实现对版本接口差异的发现和配置文件定位。
  • 前期完成了测试环境的升级,集群采用原地升级方式。

升级流程

Amazon EKS 提供了控制平面高可用全托管运行方式,基于集群运行稳定性考虑,托管节点组与控制平面之间的版本差异不能大于 1,因此 EKS 的版本升级采用逐一版本升级方式,以升级 1.21 版本到 1.23 版本为例。集群升级需要先完整升级到 1.22,然后再升级到 1.23。升级的流程设计如下:

执行过程

1. 升级前准备

1.1 环境检查

参考 Amazon EKS Kubernetes 版本更新 Amazon EKS 集群 Kubernetes 版本的官方文档,执行升级目的集群的环境检查和确认。并校验每个版本升级的先决条件。其中将集群版本更新到 1.22 的先决操作包括:

  • 更改集群中 Deployment,Service,Ingress 等资源的 YAML 清单文件和客户端以引用新的 API。
  • 更新自定义集成和控制器以调用新的 API。
  • 确保使用任何第三方工具的更新版本。这些工具包括入口控制器、服务网格控制器、持续交付系统以及调用新 API 的其他工具。

1.2 兼容性检查

Amazon EKS 集群包括了一系列的开源或第三方组件,组件的版本与集群的版本紧密相关,升级前需要确认的组件版本和兼容性配置兼容 Kubernetes 1.22,1.23 的版本。需确认的内容包括且不限于:

  • 如果您使用了 AWS Load Balancer Controller,您必须至少升级到版本 2.4.1 才能将 Amazon EKS 集群升级到 1.22 版本。
  • 部分API 版本移除:Ingress, IngressClass, Lease, APIService, ValidatingWebhookConfiguration, MutatingWebhookConfiguration, CustomResourceDefinition, TokenReview, SubjectAccessReview, and CertificateSigningRequest
  • CertificateSigningRequest(CSR)API 版本 certificates.k8s.io/v1beta1 已在 Kubernetes 版本 1.22 中删除。您必须迁移清单和 API 客户端才能使用 certificates.k8s.io/v1 CSR API。
  • Amazon EKS 旧版 Windows 支持控制器使用已在 Kubernetes 1.22 中删除的 admissionregistration.k8s.io/v1beta1 API。如果您运行的是 Windows 工作负载,您必须删除旧版 Windows 支持并启用 Windows 支持
  • App Mesh 必须升级到 App Mesh 控制器 v1.4.3 或更高版本。
  • 检查您的 CoreDNS comfigmap 是否有一行仅包含词语 upstream,若有则删除该行。
  • Kubernetes in-tree 插件至 Container Storage Interface(CSI)卷的迁移功能已启用。如果您在现有集群中使用 Amazon EBS 卷,请在将集群更新为版本 1.23 之前,在集群中安装 Amazon EBS CSI 驱动程序。如果未在更新现有集群之前安装驱动程序,则可能会中断您的工作负载。

注意,上述兼容列表仅适用于 Amazon EKS 1.21~1.23 版本,超出列表部分的组件兼容性,请查看更新 Amazon EKS 集群 Kubernetes 版本的官方文档。如图所示为升级环境的 pod 资源情况。

1.3 API 调用检查

在 Amazon EKS 集群升级的过程中,尤其关键的检查,同时也是客户非常关注的部分就是 API 的版本更新。在 Kubernetes 1.22 版本,ingress extensions/v1beta1networking.k8s.io/v1beta1 等多个 API 版本将被弃用。详细可参考已弃用的 API 迁移指南。用户需要更新客户端和各 API 调用的 yaml 文件。配置文件定义更新是否全部完成是客户非常担心的地方。本期 EKS 集群升级采用了开源工具 kube-no-trouble 进行扫描和 API 版本信息的更新。

kube-no-trouble(kubent)是一个简单的 Kubernetes 集群专项检测工具,用于根据部署资源的方式,检测您是否在集群中使用了已过期弃用的 API 版本,支持您先升级工作负载,然后再升级 Kubernetes 集群。因为 Kubernetes 的资源定义比较典型,kubent 支持以下几种定义方式的过期 API 版本检测:

本项目升级采用 kube-no-trouble(kubent)扫描 Amazon EKS 集群,根据扫描结果,定位需要更新的位置,引导客户更新已弃用 API 并重新部署资源定义。

如图所示的 kubent 扫描结果,显示 default 命名空间下有名为 nginx 的 ingress 定义正在使用已弃用的 API,需要替换为新版本 API(networking.k8s.io/v1)。根据资源部署的方式(例如 helm 或其它 CICD 工具),在资源定义文件中更新 API 版本然后重新部署(例如 helm upgrade 或 kubectl apply)。

Nginx Ingress yaml 配置文件修改前:

Nginx Ingress yaml 配置文件修改后:

以此类推,按照 kube-no-trouble 的扫描结果,将所有命名空间内,需要修改的资源定义文件完成更新。

2. 数据备份

在执行 Amazon EKS 升级变更之前,请确保对集群内的操作对象进行备份。EKS 集群中的资源对象可以采用以下几种备份及回滚方式:

  • 若应用/插件是通过 CICD 工具部署的,可以通过 CICD 工具,快速重新部署应用(建议优先使用这种方式)
  • 若应用/插件是通过 helm chart 模板部署的,可以通过 helm 重新部署或进行回滚,参考执行命令如下:
helm rollback -n <namespace> <RELEASE>

  • 若应用/插件是通过 yaml 文件部署的,可提前备份资源的 yaml 定义。例如: deployment 的资源可使用以下命令备份,其它资源如 daemonset,statefulset,service,ingress,clusterrole 等的备份方式类似。
kubectl -n <namespace> get deployment <name> -o yaml > backup.yaml

同时,Amazon EKS 支持您使用开源工具 Velero 备份 Kubernetes 集群资源和持久卷,注意在使用 velero 进行备份时,Ingress,Service LB 以及 TargetGroupBinding 资源不建议通过 velero 备份,避免恢复时导致新旧 LB 出现流量混乱的情况。备份的操作请参考 Velero 备份 EKS 官方文档

3. 版本升级

3.1 从 1.21 版本升级到 1.22 版本

3.1.1 集群控制平面升级

Amazon EKS 完全托管 Kubenetes 主节点集群服务,集群控制平面升级,可以采用 eksctl upgrade 命令直接升级。

eksctl upgrade cluster --name <cluster name> --region <region> --version 1.22 --approve

注意:升级 EKS 集群控制平面的过程中,请求 API Server 可能会出现错误,此时再次请求即可,客户端具备重试机制即可。

$ eksctl upgrade cluster —name testcluster —region ap-northeast-1 —version 1.22 —approve
2023-02-27 13:36:54 [ℹ] will upgrade cluster "testcluster" control plane from current version "1.21" to "1.22"
2023-02-27 13:47:32 [✔] cluster "testcluster" control plane has been upgraded to version "1.22"
2023-02-27 13:47:32 [ℹ] you will need to follow the upgrade procedure for all of nodegroups and add-ons
2023-02-27 13:47:33 [ℹ] re-building cluster stack "eksctl-testcluster-cluster"
2023-02-27 13:47:33 [✔] all resources in cluster stack "eksctl-testcluster-cluster" are up-to-date
2023-02-27 13:47:33 [ℹ] checking security group configuration for all nodegroups
2023-02-27 13:47:33 [ℹ] all nodegroups have up-to-date cloudformation templates

3.1.2 集群插件升级

完成 EKS 集群控制平面升级后,就可以升级集群中的插件至官方推荐版本,常见插件及版本兼容性请参考以下链接:

  1. 管理 Amazon VPC CNI plugin for Kubernetes
  2. 管理 CoreDNS 附加组件
  3. 管理 kube-proxy 附加组件
  4. aws-ebs-csi-driver
  5. aws-efs-csi-driver
  6. aws-load-balancer-controller
  7. metrics-server
  8. kube-s3

附加组件及目标版本样例参考如下:

A B C D
1 插件 当前版本 1.22 1.23
2 aws-ebs-csi-driver v1.11.4-eksbuild.1 v1.11.4-eksbuild.1 无需升级
3 coredns v1.8.4-eksbuild.2 v1.8.7-eksbuild.1 无需升级
4 kube-proxy v1.21.14-eksbuild.2 v1.22.11-eksbuild.2 v1.23.7-eksbuild.1
5 vpc-cni 1.11.3-eksbuild.1 1.11.3-eksbuild.1 无需升级
6 nvidia-device-plugin 无需升级 无需升级 无需升级
7 metric-server 无需升级 无需升级 无需升级
8 aws-load-balancer-controller v2.4.0+ v2.4.1+ 无需升级

注意:控制面升级到 1.22 之前,必须把 aws-load-balancer-controller 升级到v2.4.1或以上。

3.1.3 升级托管节点组到 1.22

托管节点组升级,支持通过如下 eksctl upgrade 直接升级节点组,也支持用户通过蓝绿的方式进行升级。

eksctl upgrade nodegroup --name <nodegroup name> --cluster <cluster name> --region <region> --kubernetes-version 1.22
$ eksctl upgrade nodegroup --name mng-2 --cluster eksworkshop-eksctl --region ap-northeast-1 --kubernetes-version 1.22
2023-03-01 07:54:43 [ℹ]  updating nodegroup stack to a newer format before upgrading nodegroup version
2023-03-01 07:54:43 [ℹ]  updating nodegroup stack
2023-03-01 07:54:44 [ℹ]  waiting for CloudFormation changeset "eksctl-update-nodegroup-1677657283" for stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:55:14 [ℹ]  waiting for CloudFormation changeset "eksctl-update-nodegroup-1677657283" for stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:55:14 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:55:44 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:56:15 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:56:15 [ℹ]  setting ForceUpdateEnabled value to false
2023-03-01 07:56:15 [ℹ]  updating nodegroup stack
2023-03-01 07:56:15 [ℹ]  waiting for CloudFormation changeset "eksctl-update-nodegroup-1677657375" for stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:56:45 [ℹ]  waiting for CloudFormation changeset "eksctl-update-nodegroup-1677657375" for stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:56:46 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:57:16 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:57:16 [ℹ]  upgrading nodegroup version
2023-03-01 07:57:16 [ℹ]  updating nodegroup stack
2023-03-01 07:57:16 [ℹ]  waiting for CloudFormation changeset "eksctl-update-nodegroup-1677657436" for stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:57:46 [ℹ]  waiting for CloudFormation changeset "eksctl-update-nodegroup-1677657436" for stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:57:47 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 07:58:17 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
...
2023-03-01 08:23:25 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-mng-2"
2023-03-01 08:23:25 [ℹ]  nodegroup successfully upgraded

节点组自动升级操作实现逻辑上是新旧版本节点的更替。集群会启动新版本节点,并逐渐删除旧版本节点,最终完成所有节点的版本更新。

3.1.4 升级非托管节点组到 1.22(Option 1:旧节点组原地升级方式)

  • 修改非托管节点组的启动模板中的 AMI 版本

在控制台上打开 EC2 > Launch templates > <template name>页面,选择 Actions > Modify template(Create new version),修改 Launch template contents > Amazon machine image(AMI),选择 1.22 版本的 AMI(通过此链接查询具体的 AMI ID,例如 ami-07393fc21d4c27aaa),点击 Create template version,此时启动模板会生成一个新版本,如图所示 version 2。

  • 修改非托管节点组的启动模板配置

在控制台上打开 EC2 > Auto Scaling Group > <group name>页面,选择 Launch template > Edit > Version,选择刚才创建的版本,如图所示 version 2。

  • 设置 1.21 版本非托管节点组的所有节点为不可调度
kubectl cordon <node1 node2 node3 ...>

  • 通过节点驱逐命令驱逐节点

逐个驱逐并删除 1.21 版本的节点。重复执行直至所有节点均被替换为 1.22 版本。

#驱逐节点
kubectl drain <node name> --ignore-daemonsets --delete-emptydir-data

#使用 node name 获取 ec2 实例 id 并删除
instanceid=$(aws ec2 describe-instances --filters "Name=private-dns-name,Values=<node name>" --region <region> | jq -r '.Reservations[0].Instances[0].InstanceId')
aws ec2 terminate-instances --instance-id $instanceid --region <region>

逐渐替换节点。

最终完成版本更新。

3.1.5 升级非托管节点组到 1.22(Option 2:新节点组替换升级方式)

  • 创建 1.22 版本的非托管节点组

通过 eksctl create nodgroup 命令创建一个 1.22 版本的新非托管节点组,用于替代 1.21 版本的旧节点组。

eksctl create nodegroup \
--cluster <cluster name> \
--name <nodegroup name> \
--node-type <nodetype, e.g. t3.small> \
--nodes <desired # of nodes> \
--nodes-min <minimum nodes> \
--nodes-max <maxmum nodes> \
--ssh-access \
--managed=false \
--ssh-public-key <ssh key name> \
--version 1.22 \
--region <region>
$ eksctl create nodegroup \
>   --cluster eksworkshop-eksctl \
>   --name umng-3 \
>   --node-type t3.medium \
>   --nodes 4 \
>   --nodes-min 0 \
>   --nodes-max 6 \
>   --ssh-access \
>   --managed=false \
>   --ssh-public-key defaultJPPEM \
>   --region ap-northeast-1 \
>   --subnet-ids subnet-0e955bd0075c40c7b,subnet-018e0eafd17d5f865 \
>   --version 1.22 \
>   --node-private-networking
2023-03-01 09:38:43 [ℹ]  nodegroup "umng-3" will use "ami-07393fc21d4c27aaa" [AmazonLinux2/1.22]
2023-03-01 09:38:43 [ℹ]  using EC2 key pair %!q(*string=<nil>)
2023-03-01 09:38:44 [ℹ]  5 existing nodegroup(s) (mng-1,mng-2,nodegroup,umng,umng-2) will be excluded
2023-03-01 09:38:44 [ℹ]  1 nodegroup (umng-3) was included (based on the include/exclude rules)
2023-03-01 09:38:44 [ℹ]  will create a CloudFormation stack for each of 1 nodegroups in cluster "eksworkshop-eksctl"
2023-03-01 09:38:44 [ℹ]  
2 sequential tasks: { fix cluster compatibility, 1 task: { 1 task: { create nodegroup "umng-3" } } 
}
2023-03-01 09:38:44 [ℹ]  checking cluster stack for missing resources
2023-03-01 09:38:45 [ℹ]  cluster stack has all required resources
2023-03-01 09:38:45 [ℹ]  building nodegroup stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:38:45 [ℹ]  deploying stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:38:45 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:39:15 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:40:06 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:40:56 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:41:57 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:42:30 [ℹ]  waiting for CloudFormation stack "eksctl-eksworkshop-eksctl-nodegroup-umng-3"
2023-03-01 09:42:30 [ℹ]  no tasks
2023-03-01 09:42:30 [ℹ]  adding identity "arn:aws:iam::625011733915:role/eksctl-eksworkshop-eksctl-nodegro-NodeInstanceRole-89UMCH5VCHDX" to auth ConfigMap
2023-03-01 09:42:30 [✔]  created 1 nodegroup(s) in cluster "eksworkshop-eksctl"
2023-03-01 09:42:30 [✔]  created 0 managed nodegroup(s) in cluster "eksworkshop-eksctl"
2023-03-01 09:42:31 [ℹ]  checking security group configuration for all nodegroups
2023-03-01 09:42:31 [ℹ]  all nodegroups have up-to-date cloudformation templates

  • 驱逐 1.21 版本的非托管节点组上的 POD

以 daemonset 方式部署或配置了 node.kubernetes.io/unschedulable:NoSchedule 容忍的 POD 仍然会调度到这些节点。

eksctl drain nodegroup --name <nodegroup name> --cluster <cluster name> --region <region>

确认 POD 已经在 1.22 版本的非托管节点组上正常启动之后,删除 1.21 版本的非托管节点组。

eksctl delete nodegroup --name <nodegroup name> --cluster <cluster name> --region <region> --approve
$ eksctl delete nodegroup --name umng-2 --cluster eksworkshop-eksctl --region ap-northeast-1                  
2023-03-01 09:51:16 [ℹ]  1 nodegroup (umng-2) was included (based on the include/exclude rules)
2023-03-01 09:51:16 [ℹ]  will drain 1 nodegroup(s) in cluster "eksworkshop-eksctl"
2023-03-01 09:51:16 [ℹ]  starting parallel draining, max in-flight of 1
2023-03-01 09:51:16 [✔]  drained all nodes: [ip-192-168-138-245.ap-northeast-1.compute.internal ip-192-168-122-180.ap-northeast-1.compute.internal ip-192-168-146-137.ap-northeast-1.compute.internal ip-192-168-116-109.ap-northeast-1.compute.internal]
2023-03-01 09:51:16 [ℹ]  will delete 1 nodegroups from cluster "eksworkshop-eksctl"
2023-03-01 09:51:17 [ℹ]  1 task: { 1 task: { delete nodegroup "umng-2" [async] } }
2023-03-01 09:51:17 [ℹ]  will delete stack "eksctl-eksworkshop-eksctl-nodegroup-umng-2"
2023-03-01 09:51:17 [ℹ]  will delete 1 nodegroups from auth ConfigMap in cluster "eksworkshop-eksctl"
2023-03-01 09:51:17 [ℹ]  removing identity "arn:aws:iam::625011733915:role/eksctl-eksworkshop-eksctl-nodegro-NodeInstanceRole-19RK5O3EQ5KOG" from auth ConfigMap (username = "system:node:{{EC2PrivateDNSName}}", groups = ["system:bootstrappers" "system:nodes"])
2023-03-01 09:51:17 [✔]  deleted 1 nodegroup(s) from cluster "eksworkshop-eksctl"

3.2 升级集群版本到 1.23

鉴于 Amazon EKS 集群升级的策略计划,EKS 1.21 版本到 1.23 版本的升级,需要逐一版本升级完成。建议用户在集群维护时间窗口内,重复本文 3.1 章节的步骤逐一升级。AWS EKS 集群控制面,组件及节点组的升级条件检查,还请参考 Amazon EKS Kubernetes 版本更新 Amazon EKS 集群 Kubernetes 版本的官方文档,进行操作前的确认。

实践结论

本文结合用户的实际运行环境和重点关注问题,采用开源检测工具 Kube-no-trouble,结合 Amazon EKS 升级的官方文档,梳理了 EKS 版本升级的明细步骤,并以图文+描述的形式给出了一个 Amazon EKS 集群的升级实际用例。从该次升级过程来看,将 EKS 集群版本从 1.21 版本升级到 1.23 版本过程中,集群中断时间小于 5 分钟,整体升级操作时间小于 30 分钟,为保障客户业务连续性,工作负载的安全性等方面提供了良好的实践参考。

参考资料

1. Amazon EKS Kubernetes 版本

https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/kubernetes-versions.html

2. Amazon EKS 集群用户手册

https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/getting-started.html

3. Kubent 开源检测工具

https://github.com/doitintl/kube-no-trouble

4. Amazon EKS 集群升级指南

https://aws.amazon.com/cn/blogs/china/amazon-eks-cluster-upgrade-guide/

本篇作者

William Yee

亚马逊云科技资深解决方案架构师。主要技术方向为云基础设施,容器和安全。具备全面的云计算技术知识和丰富的企业上云实践经验。

王祥彦

亚马逊云科技容器解决方案架构师。有丰富的中间件平台及应用容器化实践经验,熟悉 kubernetes 及云原生开源社区解决方案。