背景
Kubernetes 遵循着 N-2 支持原则,即只有最新的三个主要版本才能获得安全和错误修复更新。此外,大约每 15 周发布一个新版本。在这样的前提下,从 Kubernetes 1.19 开始,每个版本可以获得长达 14 个月的技术支持。您可以从下图中观察到最近版本的支持周期。
endoflife.date/kubernetes
让我们来看看 Ubuntu 这个传统项目的技术支持周期。对于 LTS 版本来说,可以获得将近 10 年的技术支持。因此,在使用 K8s 时,必须明白每年至少需要进行一次升级是不可避免的。否则,当遇到安全或功能问题时,将无法获得更新并进行安装使用
endoflife.date/ubuntu
说实话,这样的速度有点累人 🥲 尤其是K8s的版本更新也不仅仅是K8s本身的更新,最近几个版本更新涉及的东西也不少。一开始我很好奇其他公司真的能够跟上至少一年一次的更新吗?于是我打开了AKS、GKE和EKS的支持版本页面,发现GKE在1.19版本支持到2022年6月,而EKS目前还支持1.18版本。所以答案是业界实际上跟不太上这一年一次的更新速度 😂 但是相对频繁的更新还是无法避免的,所以我想通过这篇文章记录下自己在更新K8s时的一些步骤和经验。
总的来说
在进行升级之前,有哪些前期准备工作需要完成呢?
🛠️ 仔细阅读更新日志
首先,您需要仔细阅读 Kubernetes 官方社区发布的每个版本的“更新文件”。例如,如果您想将 K8s 1.21 升级到 1.23,您应该查看 1.22 和 1.23 的 CHANGELOG,详细研究其中的变更内容,找出对您所使用的 K8s 集群有哪些影响。
🛠️ 沟通与日程安排
由于管理和使用K8s集群的人员可能不是同一群人,例如SRE负责搭建和管理K8s集群,而后端/前端工程师负责在其上部署应用服务,因此在确定受影响范围后,如果需要其他团队或部门进行相应的修改,就需要开始沟通如何安排人力资源和制定时间表
🛠️ 生产和非生产 K8s 集群
接下来,我们需要至少有两个/群K8s集群,分别是生产环境和非生产环境。因为在升级时,我们必须先在非生产环境中运行一段时间,才能有信心在生产环境中进行升级。即使我们已经仔细查看了CHANGELOG,并且已经修改了需要修改的内容,但只有通过实际尝试,我们才能知道升级后可能会遇到什么问题。如果直接在生产环境中进行升级,可能会对线上服务造成影响。接下来,我们将更深入地讨论可能在K8s升级中遇到的一些问题,例如..
升级时如何妥善处理已弃用的 API?
👉 如何应对即将在 K8s 1.24 版本中被移除的 Dockershim?
cgroups v2 真的已经可以使用了吗?
废弃的API
大家在管理K8s Manifest的时候应该都有发现有一个参数叫做 apiVersion
,因为K8s的API一直都在不断地更新,所以旧的API就会慢慢地被弃用,最后被删除掉。以K8s 1.22为例,就有一批API要被删除掉(参考资料)。那么,当遇到这种情况时,我们应该如何升级呢?
🛠️ 存在 K8s 资源
根据官方文件和问题,我们可以发现在K8s内存在许多资源不需要为了升级而进行修改,因为升级后,K8s会自动进行向下兼容。例如,我之前使用的extensions/v1beta1或networking.k8s.io/v1beta1 apiVersion创建的Ingress,在升级到K8s 1.22后仍然能够正常运行。
🛠️ K8s 资源管理器
然而,一旦升级完成,协助建立K8s资源的角色如果想要对该K8s资源进行新增、修改或删除操作,就会遇到问题。接下来,我们以Ingress为例进行讨论:
👉 Kubernetes清单文件
假设当初是用静态的 K8s Manifest 去将此 Ingress 建立起来的,例如使用 Helm Chart,当想要使用同样的 Helm Chart 去对 Ingress 做新增/修改/删除时就可能会遇到问题,解决办法就是将 Helm Chart 内使用到的 apiVersion 修改成新的版本 networking.k8s.io/v1,或是使用下面这种可以根据不同的 K8s 版本去自动决定 apiVersion 的方式 (参考)
{{/* Get Ingress API Version */}}
{{- define "kube-prometheus-stack.ingress.apiVersion" -}}
{{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" (include "kube-prometheus-stack.kubeVersion" .)) -}}
{{- print "networking.k8s.io/v1" -}}
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
{{- print "networking.k8s.io/v1beta1" -}}
{{- else -}}
{{- print "extensions/v1beta1" -}}
{{- end -}}
{{- end -}}
👉 控制器或操作员
假设 Ingress 是由 Controller 或是 Operator 负责管理的话,那就要确保他们已经支持新版的 apiVersion,然后去研究是否需要升级该 Controller 或是 Operator。当使用静态的 K8s Manifest 来建立 K8s 资源,在遇到不支持的 apiVersion 的情况下,可以很直观地立即发现。但当使用 Controller 或是 Operator 来管理 K8s 资源时,就需要查看日志或进行测试,以确认是否正常运作
🛠️ 如何找到已弃用的 API
通常部署在K8s集群里面的东西有一大堆,有些时候升级K8s版本会有API即将要Deprecated有些版本却没有,要怎么很快速地知道目前在K8s集群内的资源在升级到某个K8s版本后,有使用到即将Deprecated的API版本呢?这时候要推荐一个开源工具Kube No Trouble(kubent)给大家,安装完之后,只要在命令提示列输入kubent,就可以从输出画面中得知哪一些K8s资源需要特别去关照,不会像是在大海捞针一般
$./kubent
6:25PM INF >>> Kube No Trouble `kubent` > 1.16 Deprecated APIs > 1.20 Deprecated APIs