【阅读原文】戳:OpenKruise社区Rollouts组件重磅更新:即插即用的蓝绿发布能力
Kruise Rollouts是OpenKruise社区提供的一个旁路组件,它能够对原始工作负载(Deployment、StatefulSet、CloneSet等)进行增强,使其具备分批发布、金丝雀发布、蓝绿发布等高级能力。蓝绿发布是Kruise Rollouts在0.6.0版本中新引入的能力。目前,Rollouts能够为Deployment以及Openkruise社区的 CloneSet两种工作负载添加蓝绿发布能力。
一. 蓝绿发布介绍
蓝绿发布是一种降低新版本上线风险的部署策略,通过维护两个相同的生产环境来实现。其中,一个环境为活跃状态(蓝色环境),对外提供服务;另一个则处于待命状态(绿色环境)。
发布时,蓝色环境继续提供服务的同时,在绿色环境中部署新版本。部署完成后,可以通过切换路由或负载均衡器将流量在两个环境间进行切换,方便验证与回滚。
下图直观地对比了蓝绿发布与金丝雀发布的流程:
二. Kruise Rollouts蓝绿发布能力介绍
2.1. 通过 Kruise Rollouts 进行蓝绿发布
本节将通过一个案例展示如何使用Kruise Rollouts 便捷地一站式管理Deployment的蓝绿发布。在本节的例子中,将当前线上的稳定版本称为“蓝色环境”,新发布的版本称为“绿色环境”。
2.1.1. 环境准备
本案例使用的环境如下:
1. Kubernetes版本:v1.28.7
2. Ingress-NGINX Controller版本:1.12.0
3. Kruise Rollouts版本:v0.6.0
2.1.2. 部署应用
通过以下的Yaml文件在K8s集群中部署了Echoserver应用:
1. 一个用于部署五个Echoserver副本的Deployment。
2. 相应的Service与Ingress用于暴露服务。
apiVersion: apps/v1 kind: Deployment metadata: name: echoserver labels: app: echoserver spec: replicas: 5 selector: matchLabels: app: echoserver template: metadata: labels: app: echoserver spec: hostname: blue # 稳定环境为蓝色环境 containers: ... --- apiVersion: v1 kind: Service metadata: name: echoserver-service spec: ... --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: echoserver-ingress spec: ...
2.1.3. 声明发布策略
在应用的同一个Namespace中,创建以下的Rollout资源,为其声明一条蓝绿发布策略。在发布时,Kruise Rollouts会依次执行该策略中包含的三个步骤,并在步骤之间暂停以供用户进行验证。
apiVersion: rollouts.kruise.io/v1beta1 kind: Rollout metadata: name: rollouts-demo spec: workloadRef: # 通过 workloadRef 指定应用工作负载 apiVersion: apps/v1 kind: Deployment name: echoserver strategy: blueGreen: # 通过 blueGreen 配置蓝绿发布策略 steps: - replicas: 100% # 第一步:拉起 100% 副本的绿色环境 traffic: 0% - replicas: 100% # 第二步:将 10% 的流量导入绿色环境,灰度验证 traffic: 10% - replicas: 100% # 第三步:将所有流量导入绿色环境,推平 traffic: 100% trafficRoutings: # 通过 trafficRoutings 指定应用的网络资源 - service: echoserver-service ingress: classType: nginx name: echoserver-ingress
通过kubectl命令查看Rollout资源状态。在没有发布任务时,Rollout处于Completed状态。
$ kubectl get rollout NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE rollouts-demo Healthy 3 Completed workload deployment is completed 8s
2.1.4. 更新应用
修改Deployment的配置,将hostname从blue改为green,进行一次更新。
apiVersion: apps/v1 kind: Deployment metadata: name: echoserver labels: app: echoserver spec: ... template: ... spec: hostname: green # 拟更新到绿色环境 ...
在更新Deployment后,Kruise Rollouts将会启动蓝绿发布流程,并自动执行第一步。当Rollout资源的CANARY_STATE状态进入StepPaused后,意味着第一步执行完毕,此时绿色环境已被拉起,集群中同时存在两个版本各五个副本。
# Rollout 状态流转 $ kubectl get rollout NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE rollouts-demo Progressing 1 StepUpgrade Rollout is in step(1/3), and upgrade workload to new version 33s $ kubectl get rollout NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE rollouts-demo Progressing 1 StepTrafficRouting Rollout is in step(1/3), and upgrade workload to new version 38s $ kubectl get rollout NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE rollouts-demo Progressing 1 StepPaused Rollout is in step(1/3), and you need manually confirm to enter the next step 41s # Pod 统计 +-----------------------------+----------+ | name | hostname | +-----------------------------+----------+ | echoserver-696b76ddd8-9mpbb | blue | | echoserver-696b76ddd8-b7qqb | blue | | echoserver-696b76ddd8-nbdc7 | blue | | echoserver-696b76ddd8-t4zgb | blue | | echoserver-696b76ddd8-vmd2z | blue | | echoserver-7d4744f99c-5mcb5 | green | | echoserver-7d4744f99c-8tgfc | green | | echoserver-7d4744f99c-bnfhc | green | | echoserver-7d4744f99c-m7n9k | green | | echoserver-7d4744f99c-x52mx | green | +-----------------------------+----------+
此时反复请求网关,可以发现虽然绿色环境已被拉起,但是所有请求依然被蓝色环境所响应。
Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue
在发布暂停时,可以通过以下两种方式进入下一步:
$ kubectl patch rollout rollouts-demo --type merge --subresource status -p "{\"status\":{\"blueGreenStatus\":{\"currentStepState\": \"StepReady\"}}}"
2. 通过Kruise命令行工具继续发布。
$ kubectl-kruise rollout approve rollouts/rollouts-demo
继续发布,开始第二步的灰度验证阶段。当Rollout资源再次进入StepPaused状态后,再次尝试请求,发现大概每十次就会有一次请求到绿色环境,说明第二步成功导入了10%的流量。
Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by blue Request served by green Request served by blue Request served by blue Request served by blue
验证无误后,再次继续发布进入第三步的推平阶段。可以看到所有流量都已经被导入了绿色环境。此时可以进行端到端测试、压力测试等最终验证。
Request served by green Request served by green Request served by green Request served by green Request served by green Request served by green Request served by green Request served by green Request served by green Request served by green
2.1.5. 快速回滚
如果应用在灰度验证阶段或推平后验证不通过,由于蓝色环境依旧保留,可以通过切流量的方式进行快速回滚。Kruise Rollouts具备在发布的任何阶段之间任意跳转的能力,因而可以在不变更配置的情况下快速回滚,降低后续发布运维的复杂性。
在这个案例中,如果在任何时候发现绿色环境不符合预期,可以通过字改Rollout资源的nextStepIndex状态回到第一步,即蓝色环境承载所有流量的状态。这个操作可以通过以下命令实现:
kubectl patch rollout rollouts-demo --type merge --subresource status -p "{\"status\":{\"blueGreenStatus\":{\"nextStepIndex\": 1}}}"
⚠️ 注意:Kruise Rollouts的编号是从1开始的,并非0。
如果经排查,发现是因为外部因素导致绿色环境不符合预期,那么在排除问题后可以继续发布:可以按照正常发布流程继续依次执行第二步、第三步,或是直接跳转到第三步进行推平。
而如果排查结论是绿色环境的变更本身包含Bug,那么可以对Deployment进行回滚操作,将其改回原先的配置:
apiVersion: apps/v1 kind: Deployment metadata: name: echoserver labels: app: echoserver spec: ... template: ... spec: hostname: blue # 绿色环境有问题,放弃发布,回滚到蓝色 ...
在蓝绿发布过程中对Deployment的Pod template进行的变更,除非改回发布前的配置(回滚),否则都不会生效。Kruise Rollouts会提示所有变更都需要先回滚再重新发布。
此时查看集群资源,发现回到了最初应用刚部署的状态,即只存在五个蓝色环境副本,Rollout资源则提示发布取消:
$ kubectl get rollout NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE rollouts-demo Healthy 1 StepReady Rollout progressing has been cancelled 20m # Pod 统计 +-----------------------------+----------+ | name | hostname | +-----------------------------+----------+ | echoserver-696b76ddd8-9mpbb | blue | | echoserver-696b76ddd8-b7qqb | blue | | echoserver-696b76ddd8-nbdc7 | blue | | echoserver-696b76ddd8-t4zgb | blue | | echoserver-696b76ddd8-vmd2z | blue | +-----------------------------+----------+
2.1.6. 发布完成
如果在第三步推平后,验证绿色环境符合预期,那么就可以再进行一次继续发布动作,完成这次发布。在发布完成后,蓝色环境将被删除,只保留绿色环境。
$ kubectl patch rollout rollouts-demo --type merge --subresource status -p "{\"status\":{\"blueGreenStatus\":{\"currentStepState\": \"StepReady\"}}}" rollout.rollouts.kruise.io/rollouts-demo patched $ kubectl get rollout NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE rollouts-demo Healthy 3 Completed Rollout progressing has been completed 31m # Pod 统计 +-----------------------------+----------+ | name | hostname | +-----------------------------+----------+ | echoserver-7d4744f99c-8wf67 | green | | echoserver-7d4744f99c-ct55j | green | | echoserver-7d4744f99c-jzwmn | green | | echoserver-7d4744f99c-lm2vs | green | | echoserver-7d4744f99c-zw4gh | green | +-----------------------------+----------+
2.1.7. 小结
本节通过案例介绍了Kruise Rollout的蓝绿发布能力,包括拉起环境、流量切换、步骤跳转、回滚等。用户无需对工作负载进行任何改造即可便捷地对应用进行蓝绿发布。
2.2. Kruise Rollouts蓝绿发布的原理
本节将通过进一步拆解3.1的示例中Kruise Rollouts进行的操作,对其蓝绿发布能力的原理进行介绍。
2.2.1. 副本管理
Kruise Rollouts通过将工作负载保持在滚动发布中的一个特殊的状态,使得两个环境得以暂时稳定共存。对于Deployment的更新,Kruise Rollouts会进行以下操作:
1. 将spec.minReadySeconds与spec.progressDeadlineSeconds设置为无穷大(具体值为2^31-1)。这样,Deployment更新永远都不会被认为失败或成功。通过将 Deployment 一直保持在更新中状态,蓝色环境与绿色环境得以共存。
2. 将spec.strategy.rollingUpdate.maxSurge设置为适当的值,这个值来自于Rollout步骤中配置的副本数(百分比或绝对值)。这个值配置了Deployment在更新时允许创建的额外Pod 数量,也就是绿色环境的副本数量。
下图的对比是Kruise Rollouts对Deployment操作的参考:
2.2.2. 流量管理
为了管理两个环境之间的流量,Kruise Rollouts会分别操作应用的Service、Ingress等网络资源。
对于Service资源,Kruise Rollouts会创建一个与原始的Service(echoserver-service)内容完全一致的拷贝(命名为echoserver-service-canary),并分别给两个Service加上pod-template-hash选择器,使原始Service选中蓝色环境,拷贝Service选中绿色环境。两个Service的差别可参考下图:
对于ingress-NGINX的入口流量,Kruise Rollouts会根据应用的Ingress拷贝一个新的Ingress资源,并根据发布步骤中配置的流量比例打上相应的流量标签。两个Ingress的差别可参考下图:
⚠️ :Kruise Rollouts集成了ingress-NGINX、ALB、Higress等Ingress Controller的流量控制规则,同时支持Gateway API与Istio。对于不同类型的入口资源类型,有不同的操作实现。此处仅供参考。
2.2.3. 资源清理
一次发布可能由许多种因素导致停止:比如发布成功、回滚、删除Rollout、禁用Rollout等。在发布停止后,Kruise Rollouts会执行以下操作对管理的资源进行清理。
⚠️:为了防止流量损失与泄漏,在不同的情况下,以下步骤的顺序可能不同
1. 恢复原始Service资源的选择器
2. 调整入口流量策略指向正确的目标
3. 恢复对工作负载的调整,根据具体情况删除蓝色环境或绿色环境的副本
因此,发布前后,集群中的资源是不变的,这也体现了Kruise Rollouts的旁路特性:不工作时对应用没有干涉。
2.2.4. 小结
本节通过拆解Kruise Rollouts针对ingress-NGINX + Deployment场景的工作流程,介绍了其蓝绿发布的基本原理。需要注意的是,针对不同流量入口与工作负载的组合,其操作的细节会有所不同,碍于篇幅所限,不再展开。
2.3. Kruise Rollouts与其他开源发布方案的对比
Argo Rollouts与Flux Flagger是比较流行的两个开源发布方案。本节将从设计理念、灵活性、迁移成本等方面将Kruise Rollouts与这两种方案进行对比,介绍更加适合使用Kruise Rolouts的场景。
2.3.1. 与Argo Rollouts对比
Argo Rollouts通过一个新的工作负载(也叫 Rollout)同时指定发布策略和Pod模板,并通过多个ReplicaSet来管理Pod。下面是Argo社区官方的通过Argo Rollouts进行蓝绿发布的例子:
apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollout-bluegreen spec: replicas: 2 selector: matchLabels: app: rollout-bluegreen template: ... strategy: blueGreen: activeService: rollout-bluegreen-active previewService: rollout-bluegreen-preview autoPromotionEnabled: false --- kind: Service apiVersion: v1 metadata: name: rollout-bluegreen-active spec: selector: app: rollout-bluegreen ports: ... --- kind: Service apiVersion: v1 metadata: name: rollout-bluegreen-preview spec: selector: app: rollout-bluegreen ports: ...
很显然地,要使用Argo Rollouts,需要对现有应用做较大的改造:
1. 需要从原先的Deployment、StatefulSet、CloneSet等工作负载迁移到Argo Rollout,对于企业的发布PaaS而言,需要做新的工作负载的对接工作
2. 需要手动维护两个Service
因而,Argo Rollouts具有相当高的迁移成本,并且会在技术上收到较大的限制,降低系统的灵活性,对上层PaaS的要求也较高。
额外地,Kruise Rollouts还拥有Argo Rollouts所不具备的热插拔能力:用户可以随时(即使在发布的任意过程中)新建、修改、删除Kruise Rollout资源,从而快速地对发布策略进行修改。Kruise Rollouts对这些异常场景的特别的优化,能够保证随意插拔Rollout资源的同时,应用的流量无损、副本满足预期。
所以,如果现有应用依赖于CloneSet等工作负载的高级能力、PaaS改造成本高、或是对发布策略的灵活性较高的要求,更适合使用Kruise Rollouts进行蓝绿发布。
2.3.2. 与Flux Flagger对比
Kruise Rollouts与Flux Flagger都是以旁路组件的形式进行工作,它们的主要区别在于对工作负载的管理上。
上图是Flux Flagger的蓝绿发布原理。Flagger会在发布时,创建一个新的工作负载运行新版本。在发布完毕后,Flagger会通过滚动更新的方式将原始工作负载下的Pod升级到新版本,再删除临时新建的工作负载。与此相对的,Kruise Rollouts采用下图的单负载模式,即通过在原始工作负载中扩容额外的副本,再删除老副本的形式完成环境切换。
Flux Flagger的蓝绿发布原理其实是与Kruise Rollouts的金丝雀发布相同的。
Flux Flagger由于存在两个工作负载,因而会对有其他针对工作负载组件存在的场景具有影响。比如,使用OpenKruise社区的WorkloadSpread组件对Pod进行分组打散,或使用VPA组件对Pod进行自动变配等场景下,都需要通过WorkloadRef来指定目标工作负载,因而这些组件无法对新环境生效。
同时,Flagger还存在另一个问题,即最终提供服务的所谓“绿色环境”与当初验证的绿色环境并不是同一个。这对无状态应用没有影响,但是如果应用是游戏服务器等有状态应用,或对Pod进行了IP绑定、云盘绑定等操作,就可能会出现问题。
因此,对于使用了其他Workload敏感的组件,或是要保证绿色环境Pod不可变的场景,更适合使用Kruise Rollouts进行蓝绿发布。
三. ACS Serverless集群在蓝绿发布场景下的优势
蓝绿发布最大的问题在于其大量的资源消耗。具体地对应到K8s中,存在以下局限性:
1. 集群中至少需要额外预留一个环境的节点资源用于拉起新环境。对于大型应用(可能消耗上百个节点)来说,浪费的资源成本不可接受。
2. 当集群中存在多个应用,且同时进行发布时,可能因为资源不足而无法拉起完整环境。
因此在生产实践中,在K8s中推广蓝绿发布可能会导致不止一倍的资源浪费,大大增加了成本。
随着云计算技术的发展,出现了阿里云容器计算服务ACS(Container Compute Service)等以Serverless形态而非通过节点交付算力的K8s产品。在使用Serverless集群时,由于按照实时Pod资源用量计费,使用蓝绿发布的应用仅会在两环境共存时产生额外费用,当蓝色环境销毁后,不会再有后续开销。同时,得益于Serverless产品的弹性能力,也不会存在因资源限制而拉不起环境从而导致发布不流畅的情况。因此,在成本节省补齐短板后,蓝绿发布可能是Serverless场景下更优秀的一种发布方式。
四. 总结
本文深入探讨了蓝绿发布的概念,剖析其优劣之处,并详细阐述了适用场景。此外,还通过一个具体案例展示了如何利用Kruise Rollouts组件来增强现有工作负载,从而实现高效的蓝绿发布策略。在实际生产环境中,企业选择何种发布方式及配套工具时,需综合考量多方面因素。最后,我们精心编制了一系列对比表格,旨在为读者提供直观且全面的参考依据。
蓝绿发布与金丝雀发布的对比:
Kruise Rollouts与其他开源方案对比(下表引用自Kruise Rollouts官方文档):
相关链接:
Kruise Rollouts蓝绿发布文档
https://openkruise.io/zh/rollouts/user-manuals/strategy-bluegreen-update/
Kruise Rollouts v0.6.0 release note:
https://github.com/openkruise/rollouts/releases/tag/v0.6.0
我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。
获取关于我们的更多信息~