摘要:集群升级是Kubernetes集群生命周期中最为重要的一环,也是也是众多使用者最为谨慎对待的操作之一。为了更好地理解集群升级这件事情的内涵外延,我们首先会对集群升级的必要性和难点进行阐述。随后我们会对集群升级前必须要做的前置检查进行逐一讲解。接下来我们会对两种常见的升级方式进行展开介绍。最后我们对集群升级的三个步骤进行讲解,帮助读者从理论走入实践。
升级的必要性&难点
在 Kubernetes领域,得益于活跃的开源社区,Kubernetes 的迭代速度较快,目前保持在每个季度发行一个新版本的节奏。新版本的 Kubernetes 有着更为先进的新特性、更加全面的安全加固和漏洞修复。前一段时间社区刚刚完成了1.19版本的正式发布。
那么对于如此快速发展的开源项目,跟上社区的步伐就显得更为重要。而集群升级能力就是帮助我们跟上社区步伐的不二选择。我们可以从以下两个方面对集群升级的必要性进行说明:
- 对于Kubernetes集群的使用者。更新的Kubernetes版本意味着更新的feature,更加全面的安全补丁,和诸多的bugfix。我们可以通过集群升级功能充分享受活跃的Kubernetes开源社区带来的发展红利。
- 对于Kubernetes集群的运维者。通过集群升级功能可以拉齐所管理的集群的版本,减少集群版本的碎片化,从而减少Kubernetes版本碎片化带来的管理成本和维护成本。
讲完了集群升级的必要性,我们来详细看一下集群升级的难点。目前多数Kubernetes使用者对集群升级这件事持有者非常保守的态度,害怕集群在升级的过程中出现不可预期的情况。也有使用者将集群升级称之为“给飞行中的飞机换引擎”。那么,使用者对于升级的保守态度主要来源于什么原因呢?我认为有以下几点:
- 经过长时间的运行后,Kubernetes集群已经累计了复杂的运行时状态。
- Kubernetes集群运维者会根据集群承载的不同业务,对集群进行不同的配置。从而导致每个集群都有自己的差异化配置,可能会造成“千集群千面”。
- 对于云上运行的Kubernetes集群来说,其使用了大量的云计算底层资源。众多的底层云资源就会带来众多的不确定性因素。
由于“千集群千面”的情况的存在,就导致了集群升级需要以一套逻辑完成各种不同情况集群的升级工作,这也正是集群升级的困难之处。
升级预检
正如我们前面所说的给正在对外提供服务的Kubernetes集群升级,就好比是“给飞行中的飞机换引擎”。因为集群升级面临着众多难点,也使得众多的Kubernetes集群维护者对集群升级这件事情比较紧张。
我们可以通过详细的升级预检,来消除集群升级的不确定性。感觉上面我们列举的集群升级的难点,我们也可以分别进行详细的升级预检,对症下药,将难点逐一击破。升级预检主要可以分为三个方面:核心组件健康检查、节点配置检查和云资源检查。
核心组件健康检查
说到核心组件健康检查,就不得不剖析一下集群的健康对于集群升级的重要性。一个不健康的集群很可能会在升级中出现各种异常的问题,就算侥幸完成了升级,各种问题也会在后续使用中逐渐凸显出来。
也有的人会说,我的集群看起来挺健康的,但是升级之后就出现问题了。一般来说,之所以会发生这种情况,是因为在集群在升级之前,这个问题已经存在了,只不过是在经历了集群升级之后才显现出来。
在了解了核心组件健康检查的必要性之后,我们来看一下都需要对那些组件进行检查。
- 网络组件:需要确保网络组件版本和需要升级到的目标Kubernetes版本兼容。
- apiservice:需要确保集群内的apiservice都可用。
- 节点:需要确定节点全部健康。
节点配置检查
节点作为承载Kubernetes的底层元计算资源,不仅运行着Kubelet、Docker等重要的系统进程,也充当着集群和底层硬件交互接口的角色。
确保节点的健康性和配置的正确性是确保整个集群健康性重要的一环。下面就对所需的检查项进行讲解。
- 操作系统配置:需要确定基础的系统组件(yum、systemd和ntp等系统服务是否正常)和内核参数是否配置合理。
- kubelet:需要确定kubelet的进程健康、配置正确。
- Docker:需要确定Docker的进程健康、配置正确。
云资源检查
运行在云上的Kubernetes集群依赖着众多云资源,一旦集群所依赖的云资源不健康或者配置错误,就会影响到整个集群的正常运行。我们主要需要对下列云资源的状态和配置进行预检。
- apiserver所使用的SLB:需要确定实例的健康状态和端口配置(转发配置和访问控制配置等)。
- 集群所使用的VPC和VSwitch:需要确实实例的健康状况。
- 集群内的ECS实例:需要确定其健康状况和网络配置。
两种常见的升级方式
在软件升级领域,有两种主流的软件升级方式,即原地升级和替换升级。这两种升级方式同样适用于 Kubernetes 集群。这两种集群升级方式采用了不同软件升级思路,这两种升级方式也都存在着各自的利弊。下面我们来对这两种集群升级方式进行逐一讲解。
原地升级
原地升级是一种精细化的、对这个那个集群改动量相对较小的一种升级方式。在升级容器的的worker节点的时候,该升级方式会通过在 ECS 上原地替换 Kubernetes 组件的方式(主要为kubelet和其相关组件),完成整个集群的升级工作。阿里云容器服务Kubernetes 为客户提供的集群升级就是基于这种方式的。
以将Kubernetes的版本从 1.14 升级到 1.16 为例。首先我们会对ECS A上的原本为 1.14 的Kubelet 及其配置升级为1.16,在完成节点ECS A 上的组件升级之后,该节点也就被成功的升级到了1.16。然后我们再对ECS B进行相同的操作,将其升级为1.16,从而完成整个集群的升级工作。在这个过程中节点保持运行,ECS 的相关配置也不会被修改。如图所示。
优点:
- 原地升级通过原地替换kubelet组件的方式对节点进行版本升级,从而保证了节点上的 Pod 不会因为集群升级而重建,确保了业务的连贯性。
- 该种升级方式不会对底层 ECS 本身进行修改和替换,保证了依赖特定节点调度的业务可以正常运行,也对 ECS 的包年包月客户更加友好。
缺点:
- 原地升级方式需要在节点上进行一系列升级操作,才能完成整个节点的升级工作。这就导致整个升级过程不够原子化,可能会在中间的某一步骤失败,从而导致该节点升级失败。
- 原地升级的另一个缺点是需要预留一定量的资源,只有在资源足够的情况下升级程序才能在ECS 上完成对节点的升级。
替换升级
替换升级又称轮转升级,相对于原地升级,替换升级是一种更加粗狂和原子化的升级方式。替换升级会逐个将旧版本的节点从集群中移除,并用新版本全新的节点来替换,从而完成整个Kubernetes 集群的升级工作。
同样以将Kubernetes的版本从 1.14 升级到 1.16 为例。使用替代轮转方式的情况下,我们会将集群中1.14 版本的节点依次进行排水并从集群中移除,并直接加入 1.16 版本的节点。即将1.14节点的ECS A从节点剔除,并将1.16节点的ECS C加入集群,再将ECS B从集群中删除,最后将ECS D加入到集群中。这样就完成了所有节点的轮转工作,整个集群就也就升级到 1.16 了。如图所示 。
优点:
替代升级通过将旧版本的节点替换为新版本的节点从而完成集群升级。这个替换的过程相较于原地升级更为原子化,也不存在那么复杂的中间状态。所以也不需要在升级之前进行太多的前置检查。相对应的,升级过程中可能会出现的各种稀奇古怪的问题也会减少很多。
缺点:
•替代升级将集群内的节点全部进行替换和重置,所有节点都会经历排水的过程,这就会使集群内的pod 进行大量的迁移重建。对于 pod 重建容忍度比较低的业务、只有单副本的应用、stateful set等相关应用不够友好,可能会因此发生不可用或者故障。
•所有的节点经历重置,储存在节点本地磁盘上的数据都会丢失。
•这种升级方式可能会带来宿主机IP变化等问题,对包年包月用户也不够友好。
集群升级三部曲
一个 Kubernetes 集群主要由负责集群管控的 master,执行工作负载的worker和众多功能性的系统组件组成。那么对一个 Kubernetes 集群升级,也就是对集群中的这三个部分进行分别升级。故集群升级的三部曲为:
- 滚动升级 master
- 分批升级 worker
- 系统组价升级(主要为CoreDNS,kube-proxy等核心组件)
下面我们来对集群升级三部曲进行详细的讲解。
滚动升级 master:
master作为集群的大脑,承担了与使用者交互、任务调度和各种功能性的任务处理。集群master的部署方式也比较多样,可以通过static pod进行部署,可以通过本地进程进行部署,也可以通过Kubernetes on Kubernetes的方式在另一个集群内通过pod的方式部署。总而言之,无论master为哪种部署方式,想要手机master就是主要就是对 master 中的三大件进行版本升级,主要包括:
- 升级 kube-apiserver
- 升级 kube-controller-manager
- 升级 kube-scheduler
需要注意,为了保证 Kubernetes apiserver 的可用性不中断,master中的 kube-apiserver 最少需要有两个,这样才可以实现滚动升级,从而保证apiserver不会出现downtime。
分批升级 worker:
在完成master的升级工作之后,我们才可以开始对worker进行升级。Worker 升级主要是对节点上的kubelet 及其依赖组件(如cni 等)进行升级。为了保证集群中worker 不会同时发生大批量的 kubelet 重启,所以我们需要对 worker节点进行分批升级。
需要注意,我们必须要先升级master,再升级worker。因为高版本的kubelet在连接低版本的master时,很可能会出现不兼容的情况,从而导致节点not ready。对于低版本的kubelet连接高版本的apiserver,开源社区保证了apiserver对于kubelet两个版本的向后兼容性。即1.14的kubelet可以连接到1.16的apiserver,而不会发生兼容性问题。
核心系统组件:
为了保证集群中各个组件的兼容性,我们需要在升级集群的同时对集群中的核心系统组件进行同步升级,主要包括
- Dns 组件:根据社区的版本兼容矩阵(https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md),将 CoreDNS 的版本升级为与集群版本相对应的版本。
- 网络转发组件:Kube-proxy的版本是跟随Kubernetes的版本进行演进的,所有我们需要将kube-proxy的版本升级到与Kubernetes版本相同的版本。