导语:随着云原生理念在企业中的深入和践行,应用容器化的比例大幅提升。是否可以保证应用容器化迁移过程中的平稳切换,保证应用不停机迁移,成为影响用户业务云化的一个重要条件。本文整理自阿里云云原生团队在KubConChina线上峰会的分享实录,将通过集群迁移的需求、场景以及实践方式,介绍如何基于阿里云容器服务ACK,在零停机的情况下迁移Kubrnts集群。
大家好,我是谢瑶瑶,来自阿里云,目前是Cloud-providr开源子项目cloud-providr-alibaba-cloud项目的Maintainr。今天由我和我的同事顾静一起为大家分享如何不停机的迁移Kubrnts集群。顾静同学也是cloud-providr-alibaba-cloud项目的Maintainr。
我们将从上图几个方面来分享如何不停机的迁移Kubrnts集群。首先我们会为大家介绍一下集群迁移的需求以及应用场景;接着我们会着重介绍如何实现不停机地Kubrnts集群迁移,包括如何进行迁移前的前置检查,如何做应用的数据迁移与流量迁移等等。
为什么要迁移Kubrnts集群?
下面简单介绍下集群迁移的应用场景。
容器化的应用迁云
首先我们来看一下容器化的应用迁移场景。近年来云原生理念已经逐渐深入到了各大公司中。据相关调查统计,将近有65%的应用已经实现了容器化,并逐步从线下的数据中心迁移到了云上,以便充分利用云的弹性来实现企业的降本增效。是否可以保证应用容器化迁移过程中的平稳切换,保证应用不停机迁移,成为影响用户业务云化的一个重要条件。
跨云同步与迁移
其次是混合云场景下的跨云流量迁移。对用户来讲,如果云是一个极具性价比的选择的话,那么混合云和多云的架构进一步为用户提供了一个低成本全球可达的应用发布平台。多云可以让用户的应用部署到多个云厂商,避免厂商锁定。同时它能够提供更高的议价能力、更强的备份、灾难恢复能力和更强的稳定性。同时还可以为全球用户提供基于地理位置的就近服务体验。如何进行不停机跨云同步机迁移是部署跨云/多云应用的前提。
集群新特性与BrakingChang场景
更高的Kubrnts版本往往会具有更多的新特性,但是使用这些新特性并不是没有代价的。如果你需要使用新特性,那就必须升级Kubrnts到对应的新版本。这通常不是一件容易的事情。如果你的集群版本太低,那么你需要多次升级集群才能到达预期的版本。比如从1.14依次升级到1.16,然后是1.18,然后才是1.20,这样来避免单次升级集群版本过大造成的兼容性问题。并且这些新特性所引入的兼容性问题还可能造成服务中断。
除了升级困难以及版本兼容性问题,升级已有集群无法实现一些配置变更类的需求。比如你无法直接变更一个已有集群的网络模式,比如从IPTabls切换到IPVS,Flannl到Trway,更改ClustrCIDR等。这些变更会造成整个集群已有节点及Pod的重建,造成服务不可用,甚至是整个集群配置被污染。因此不停止迁移Kubrnts集群应用在这种情况下可能是一个更好的选择。
接下来我们介绍一下如何进行不停机迁移。不停机迁移总体上分为3个阶段。
第一阶段:前置检查,提前暴露迁移可能存在的潜在风险;第二阶段是应用迁移,这一阶段需要新建一个目标版本的集群,并将应用及其数据迁移到新的集群中;第三阶段是流量迁移,这一阶段至关重要,他决定了如何不停机地将线上流量导入到新建的集群中,并使用新建的集群为用户提供服务。
首先在前置检查阶段,我们需要尽早的暴露迁移风险,因此我们开发了一套前置检查框架,用来检查集群是否做好了迁移准备。比如不同版本的集群会有APIgroups兼容性,需要提前处理Labl的兼容性,不同版本的组件的行为差异等,如kubproxy处理SLB流量转发的行为差异,会直接影响流量迁移的成功。因此前置检查是一项非常重要的步骤。
前置检查项都通过后,接下来就是应用的迁移与流量迁移。
应用的迁移可以通过开源组件Vlro进行,官方有详细的文档来说明应用的迁移,阿里云也专门为其提交了阿里云相关驱动。这里我们主要介绍一下如何做数据迁移,数据迁移是实现不停机迁移的重要一环,我们会以磁盘存储和有状态应用MySQL/ETCD的迁移为例,来说明如何进行数据的迁移。
通常云上的存储主要有NFS、OSS对象存储、CloudDisk云盘等,通常各大云厂商都为磁盘类型的存储提供了完善的快照方法及恢复方法。上图展示了如何将上海Rgion的应用数据迁移到杭州Rgion的方法,对于磁盘存储类型,首先在上海Rgion构建磁盘快照,然后将快照通过云厂商的网络同步到待恢复的地域杭州,然后通过快照恢复功能创建一块磁盘,然后挂在到节点上后应用即可随时使用。
对于自建MySQL/ETCD一类的应用数据,由于其持续读写可能造成潜在的数据不一致的情况,我们可以通过为该应用在目标Rgion构建多个Slav副本(或者quorum副本),用来进行实时数据同步,当流量低峰期到来的时候,执行主从切换,或者强制选主流程。一旦目标Rgion选主完成,则代表切换完成,可以逐步下线原Rgion的MySQL或ETCD副本。这就是一个简单的数据迁移流程。
接下来介绍一下流量迁移部分。流量迁移是集群迁移中十分重要的环节。流量迁移是指在业务流量无中断的前提下,将业务流量从一个集群迁移到另一个集群中去。客户端对流量迁移应当完全无感。
DNS是实现无损流量迁移的一种方式。分别在两个集群中创建两个LoadBalancr类型Srvic,然后将两个SLB添加到DNS后端,基于DNS的灰度能力实现流量分发到两个不同的集群中。这种方式较为简单,但是有一个比较大的缺陷,DNS缓存有过期时间,流量切换后需要等待30分钟左右才能生效。当在新集群中进行业务回滚时,这个延迟不可接受的。
另外一种流量迁移方式是基于Istio实现的。Istio方式比较复杂,学习成本比较高。需要新建一个Istio集群,并且更改已有的应用部署方式,然后基于Istio的灰度能力进行流量迁移。
那么有没有一种方式,操作简单又可以实现实时无损流量迁移呢?
如何在零停机的情况下迁移Kubrnts集群
为了解决这个问题,我们还得从服务暴露方式入手。LoadBalancr类型的Srvic实际是通过云上负载均衡器对外部暴露服务的。负载均衡器是由各云服务提供商通过部署在集群中的controllr创建的,创建出来的负载均衡器的信息会显示在Srvic的status.loadBalancr字段中。请求访问云上负载均衡器时,由各云厂商负责将流量重定向到后端Pod上。
CloudControllrManagr(CCM)就是阿里云容器服务部署在Kubrnts集群中的controllr,负责对接Kubrnts资源及云上基础产品,如SLB、VPC、DNS等。对于SLB,CCM支持两种流量转发方式,一种是ECS模式,一种是ENI模式。ECS模式将NodIP和NodPort挂载到SLB后端,流量经由SLB转向Nod,然后经过节点的kub-proxy转发至Pod上。ENI模式将PodIP及TargtPort挂载到SLB后端,流量经由SLB直接转发到Pod上。与ECS模式相比,ENI模式少了一层网络转发,网络性能更好。流量转发模式与Kubrnts中网络插件有关,Flannl网络插件默认为ECS模式,Trway网络插件默认为ENI模式。
那么CCM是如何管理SLB的呢?
对于LoadBalancr类型的Srvic,CCM会为该Srvic创建或配置阿里云负载均衡SLB。CCM首先会查询KubrntsSrvic信息,构建Localmodl,然后查询SLB信息,构建Rmotmodl。对比两个modl的差别,根据Localmodl更新Rmotmodl,直到两个modl一致。当Srvic对应的Endpoint或者集群节点发生变化时,CCM会自动更新SLB的虚拟服务器组中的后端。此外,CCM还提供了许多阿里云特定注解,支持丰富的负载均衡能力。
当用户访问srvic时,如果在集群内部,经由srvic转发至Nod,经过kub-proxy转发到Pod。如果访问负载均衡ip时,则通过SLB后转发至节点Nod或者Pod上。
了解LoadBalancrsrvic工作原理后,能不能通过CCM实现实时无损流量迁移呢?答案是可以的。将两个集群的节点加入到同一个SLB的同一个端口中,然后通过修改两个集群所占权重即可实现流量迁移。对于客户端来讲,访问的仍然是以前的SLBip和port,完全无感。
具体操作如下:首先在1.14集群中创建一个Srvic,指定已有SLB及端口,以及端口关联的虚拟服务器组。然后在1.20集群中创建一个Srvic,指定同样的SLB、端口及虚拟服务器组。通过wightannotation为两个集群设置权重。
配置完成后,流量转发方式如上图所示。有80%的流量转发到1.14集群中,20%的流量转发到1.20集群中。
两个集群共用SLB的同一个端口。通过修改Srvic中的wightannotation可以动态实时修改流向两个集群的流量比例,实现灰度流量迁移。当迁移完成后,从1.14集群中删除Srvic即可。
设置权重annotation后,如何保证集群内Pod负载均衡呢?
对于xtrnalTrafficPolicy为Clustr的srvic,CCM会将所有节点加入到SLB后端。每个节点的权重为wight/NodNum。此时,Nod1,Nod2,Nod3权重均为27,但是三个节点上的Pod数量并不均衡,那么如何实现Pod负载均衡呢?Clustr模式是依赖kub-proxy实现的。在clustr模式下,kub-proxy会将所有Pod信息写入到本地的转发规则中,并以轮训的方式向这些Pod转发请求。以Nod3为例,该节点上没有Pod,当请求发送到Nod3节点后,kub-proxy会将请求转发给Nod1或者Nod2。
对于xtrnalTrafficPolicy为Local的srvic,CCM仅会将Pod所在节点加入到SLB后端。因为如果节点没有Pod,当请求转发至该节点时,请求会被直接丢弃。Local模式下,需要先计算每个Pod的权重,即PrPodWight=Wight/TotalPodNum。节点权重为NodPodNum*PrPodWight。Nod1为50,Nod2为30。由于每个Pod的权重都为10,因此Pod间可以实现负载均衡。
基于CCM的流量迁移方案不仅适用于云上集群迁移,还适用于混合云、跨Rgion迁移及跨云迁移场景。以混合云场景为例,客户可以将线下ECS加入到SLB后端,然后通过设置权重逐步将流量从线下集群迁移到线上集群中,无需进行业务改造,客户端也是完全无感的。
在新集群中测试时不可避免的会遇到应用更新的场景。如果保证应用更新的过程中流量无损呢?
应用更新分为两个步骤,创建新的Pod,等待Podrunning后,删除旧的Pod。新的Pod创建成功后,CCM会将其挂在到SLB后端,如果新建的Pod无法提供服务,那么请求就会失败。因此,需要为Pod添加就绪检测。仅当Pod可以对外服务时,才将其加入到SLB后端。在删除Pod时也会遇到同样的场景。因为Pod删除和从SLB后端移除Pod是异步进行的,如果Pod以及删除,但是还未从SLB后端移除,就会出现请求转发到后端,但是无Pod处理导致请求失败的情况。因此需要为Pod添加prstophook。
Pod优雅退出过程如上图所示。首先kubltdltpod,然后ndpointcontrollr更新ndpoint。更新完毕后,kub-proxy移除节点转发规则。CCM检测到ndpoint更新事件后,从SLB后端移除Pod。在apisrvr删除Pod时,kublt同时开始删除Pod逻辑,触发Podprstop。在prstop结束后发送sigtrm信息。在整个Pod优雅退出过程中,直到CCM从SLB后端移除Pod之前一直会有新的流量进入。
由于CCM与kub-proxy是异步进行的,因此会出现SLB还未移除Pod,kubproxy已经将节点转发规则清理的情况。此时,请求进入SLB后,转发至Nod上,由于kub-proxy已经将路由规则清理了,所以该请求无法处理。将srvic改为clustr模式可以解决这一问题。如果Srvic一定需要为local模式,那么需要保证一个节点上有多个Pod。也可以通过设置Srvic为ni模式解决这一问题。
总结来说,集群迁移可以分为如下三个步骤,前置检查、应用迁移及流量迁移三个步骤。前置检查需要检查不同集群间api/Nodlabl等兼容性,应用迁移可以使用开源工具进行,基于CCM则可以实现实时无损流量迁移。
作者:顾静(子白)|阿里云高级研发工程师;谢瑶瑶(初扬)|阿里云技术专家
原文链接: