作者:明昼
前语
Kruise Rollout是 OpenKruise 社区开源提出的一个渐进式交付框架。其规划理念是供给一组能够将流量发布与实例灰度相结合,支撑金丝雀、蓝绿、A/B Testing等多样化发布方法,以及支撑依据 Prometheus Metrics 等自定义 Metrics 完结发布过程自动化,无感对接、易扩展的旁路式规范 Kubernetes 发布组件。
github.com/openkruise/…
在最新发布的 Kruise Rollout 0.3.0 版别中,咱们为大家带来了几个十分有趣的新特性:一是针对 Kubernetes 社区应用最为广泛的 Deployment 作业负载的发布才干进行了重磅增强;二是对流量灰度才干进行了进一步扩展;三是支撑以刺进 Lua 脚本的方法来支撑更多网关协议的扩展:
- Deployment 分批发布:Deployment 能够像 StatefulSet 或 CloneSet 一样具有分批发布 Pod 的才干。
- 依据 Header&Cookie 南北向流量灰度:答应用户在发布时对七层流量依照 Header&Cookie 匹配规矩进行区分,并将不同流量集体导入不同版别实例,以便对新特性进行 A/B Testing 或进行更细粒度的流量调度。
- 依据 Lua 脚本的 Ingress 流量扩展:答应用户以装备 Lua 脚本的方法,为更多类型的流量组件拟定 Kruise Rollout 插件,支撑更多类型的 Ingress 扩展协议。
概念说明
在介绍新特性之前,让咱们先一起整理一下现在 Kubernetes 作业负载主流的发布方法:
- 翻滚晋级:原生 Deployment 自带的主流发布方法,流式翻滚晋级,无法设置卡点。
-
- 优势:发布功率高;
- 下风:爆破半径大,简单呈现大规模发布毛病。
- 金丝雀发布:Flagger 和 Kruise Rollout 等组件都支撑的一种针对 Deployment 的发布方法,在发布时会创立一个金丝雀版别的 Deployment 进行验证,当验证通往后,再进行全量的作业负载晋级,并删去金丝雀版别的 Deployment。
-
- 优势:回滚无需重建或重新发布 Pod,所以回滚十分快速和便利;
- 下风:发布时需求额定的资源消耗,而且需求重复发布新版别 Pod,发布时不能彻底兼容 HPA。
图 1:金丝雀发布方法
- 规范分批发布:凭借相似 StatefulSet 或 CloneSet 供给的 Partition 才干完结的规范方法的分批发布,发布时始终保持原作业负载称号等元特点不变,而且不会裂变出其他作业负载。
-
- 优势:发布不浪费资源,可操控爆破半径,可彻底兼容 HPA 等需求 Ref 作业负载的其他组件;
- 下风:Deployment 很难支撑此类型发布(现在仅知 Kruise Rollout 支撑 Deployment 进行此类型发布)。
图 2:规范分批发布方法
-
非规范分批发布:由于 Deployment 原生逻辑无法支撑分批才干,所以像 KubeVela 等社区提出的 Rollout 计划,运用的是两个 Deployment 翻滚的方法进行发布。每次发布时都会创立新的 Deployment,而且对 Deployment 扩容的同时,缩容旧的 Deployment,相当于每次发布完结后 Deployment 都会被替换。
-
- 优势:发布时不需求额定资源,可操控爆破半径;
- 下风:发布时会裂变多个作业负载导致缺少统一操控平面,简单形成发布和扩缩动作相冲突,难以兼容 HPA 等场景,简单形成发布卡单。
图 3:非规范分批发布方法
- A/B Testing:依照一定的规矩将用户流量切分成 A、B 两个不相交通路,并将导入不同版别的 Pod 实例进行处理,以此来更好地调查、比照或者灰度新版别才干。一般来说,A/B Testing 需求结合金丝雀发布或分批发布进行。
图 4:A/B Testing
计划比照
关于上述发布方法,除了 Deployment 自带的翻滚晋级“一把梭”的方法不需求依靠其他三方组件之外,其余发布方法或多或少都需求依靠其他组件或上层 PaaS 平台的才干支撑。那么 Kruise Rollout 作为其间的一种处理计划,与其他计划相比,又有何优缺点?下面咱们比较了开源社区现在相对较为流行的两种处理计划:Flux 社区提出的**Flagger [ 1] **,以及 Argo 社区提出的Argo-Rollout [ 2] :
总的来说,Kruise-Rollout 的优势能够总结为以下几点:
- 灵活性:具有旁路式可插拔才干,即,当用户下发 Kruise Rollout 装备后,对应的 Deployment 会马上具有规范分批发布的才干;当用户不在需求该才干时,可随时删去 Kruise Rollout 装备(甚至在发布过程中也能够删去),Deployment 马上会康复至原生翻滚发布行为。
- 兼容性:完美兼容 HPA 或其他需求 Ref Workload 的三方组件;
- 接入简洁:由于 Kruise Rollout 极具灵活性,用户只需求下发装备即可收效,用户无需做任何 Pod 或 Workload 的搬迁作业,对存量运行时容器无影响,不影响扩缩容链路,故接入相对十分简洁。
特性介绍
在介绍新特性之前,再啰嗦一下为什么 OpenKruise 社区要执着于做 Rollout 这件工作。
- 咱们知道在 Kubernetes 中,容器生命周期与流量生命周期异步办理的规划使得 Deployment 自身无法感知流量的挂载与卸载,咱们曾遇到某客户在一次 Deployment 流式翻滚晋级过程中,流量组件呈现异常,导致流量悉数挂空的事故,尽管只要短短十几分钟,但却也形成了十分大的损失。
- 事务逻辑导致的 Bug 在 Deployment 流式翻滚更新的发布阶段无法感知,一旦全量上线后,可能会形成严峻毛病,很难操控毛病的爆破半径(由于 Deployment 翻滚晋级只要 Pod 可用就会全量发布)。
- 咱们也常常遇到在测试环境中跑的好好的,为什么到了出产却不行了之类的问题。其实只靠环境阻隔处理不了一切问题,出产发布环境最好仍是不要晋级“一把梭哈”,按部就班才干“一步一个脚印”。
上述场景假如运用分批的发布方法,其实是能够尽可能地将问题的爆破半径操控在灰度规模之内,而且能够留下足够的灰度和调查的时间。然而,Deployment 原生逻辑并不支撑分批操作,但假如运用 Argo-Rollout,还需求把一切作业负载和 Pod 进行搬迁,风险太高,而且适配也太费事;假如运用 Flagger,仍然要搬迁 Pod,而且发布时候还需求双倍资源,价值也太高。
这时候,你需求的可能是 Kruise-Rollout !仅需两步,就能够让你的存量 Deployment 马上具有规范分批发布才干!
新特性一:教你玩转 Deployment 规范分批发布
前置过程
存量或新建 Kubernetes 集群并要求:
- Kubernetes version >= 1.19
注:该版别要求主要是 Ingress API 在 1.19 有较大变动所引起,假如你不需求复杂的流量灰度的才干(即不需求装备 TrafficRouting 字段),能够自行拉取和修正 charts,来躲避该版别要求。
过程一:一键装置 Kruise-Rollout
$ helm install kruise-rollout openkruise/kruise-rollout –version 0.3.0
过程二:为你的 Deployment 绑定并下发分批发布规矩
cat <<EOF | kubectl apply -f -
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
namespace: default
annotations:
rollouts.kruise.io/rolling-style: partition
spec:
objectRef: # 绑定你的 Deployment
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: echoserver
strategy: # 拟定你的分批发布规矩
canary:
steps:
- replicas: 1 #第一批发一个 Pod,发布完后暂停,手动承认后进入下一批
- replicas: 60% #第二批发60% Pod,发布完后暂停,手动承认后进入下一批
- replicas: 100% #第三批发全量 Pod,最终一批发布完后默许自动完结
EOF
过程三:玩转 Deployment 的分批发布
如此一来,当你后续进行发布时,Deployment 的流式翻滚晋级将会直接变为分批发布。下面咱们以一个名为 echoserver 的 Deployment 为例,描绘一次分批发布过程。
1. 发布前
检查一下 Deployment 副本数为 5,当前版别为 789b88f977:
2. 开端发布第一批
此刻,咱们修正容器的某个环境变量来触发发布,能够看到第一批只发布了一个 Pod,版别号为 d8db56c5b:
3. 持续发布第二批
第一批 Pod 发布完毕后,此刻假定咱们现已完结第一批的验证,想要持续发第二批 Pod,咱们能够凭借 kubectl-kruise 这个命令行东西来进行批次完结的承认操作。该东西是依据 kubectl 的拓宽,现在也是由 OpenKruise 社区维护。
注:承认发下一批的命令为 kubectl-kruise rollout approve rollout/rollouts-demo
从上述过程能够看出,在该批次发布过程中且未完结时,Rollout 会进入 StepUpgrade 状况,而当该批次发布完结,会转变成 StepPaused 状况。
4. 发布最终一批
当第二批发布承认完结后,发最终一批后,Rollout 会进入 Completed 状况,表明发布完结:
特别要说明的是,在分批发布的单个发布批次内,咱们仍然会遵从流式翻滚发布的规矩,也就是说你仍然能够经过调整 Deployment 的MaxUnavailable和MaxSurge来兼顾你发布时的稳定性和功率,例如在以下场景,你依然能够遵从 Deployment 的如下装备:
- 单个批次内有必要先扩后缩,最大程度确保发布稳定:
kind: Deployment
spec:
strategy:
rollingUpdate:
maxUnavailble: 0
maxSurge: 20%
- 单个批次内有必要先缩后扩,最大程度节约 资源占用:
kind: Deployment
spec:
strategy:
rollingUpdate:
maxUnavailble: 20%
maxSurge: 0
- 单个批次内边扩遍缩,最大程度进步发布功率:
kind: Deployment
spec:
strategy:
rollingUpdate:
maxUnavailble: 25%
maxSurge: 25%
此外,该计划还充分考虑了各种发布场景,最大程度地进步计划的灵活性:
- 连续发布场景:v1 到 v2 的发布过程中(v2 未发布完结),又发布了 v3,此刻 v3 仍然会从第一批开端走规范分批发布流程;
- 快速回滚场景:v1 到 v2 发布到半途,回滚回 v1,则会进行快速回滚,默许不再进行分批发布。
- 发布战略删去:无论是在发布完结后,甚至是在发布过程中,正常删去 Rollout 资源后,相应的 Deployment 都会无缝回退至流式翻滚发布场景,便利某些特别情况下快速进行改变。
新特性二:依据 Header&Cookie 的流量灰度
在 Kruise-Rollout 0.3.0 之前的版别中,咱们供给了依据调整流量权重 (Weight) 的流量灰度计划,但是考虑到在实际大多数场景中,各类 Ingress 等自身现已具有的载均衡才干就能满意日常流量灰度的需求,例如 10% 的 canary 副本自身就会默许打入 10% 的流量,假如不是特别的精细化流量调整场景( 例如 10% 的 canary 副本只导入 1% 流量),一般不需求独自装备该才干。
但是,关于一些发布敏感性事务,是可能需求 A/B Test 等这类特别的发布方法:即在发布时,需先将特定的一批带有标记的流量,定向导入新版别 Pod,将新旧版别的流量进行阻隔,比方如下场景:
- 事务新特性只对白名单用户开放,能够很大程度减少事务新特性的不确定性带来的风险;
- 将新旧两个版别进行流量阻隔,便利进行对照试验,更好地调查新版别特性的有效性;
关于 Kruise-Rollout 的用户来说,能够经过以下装备来开启该才干:
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
namespace: default
annotations:
rollouts.kruise.io/rolling-style: partition
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: echoserver
strategy:
canary:
steps:
- matches: #设置 header&cookie 匹配规矩
- headers:
- name: UserAgent
type: Exact
value: iOS
pause: {}
replicas: 1
- replicas: 50%
- replicas: 100%
trafficRoutings:
- ingress:
classType: nginx
name: echoserver
service: echoserver
上述相较于单纯的分批发布装备,多了 Header & Cookie 匹配规矩的描绘,以及 TrafficRouting 的引用,这儿是以 Ingress-Nginx 为例进行的装备,也就是说,想要运用该才干,相应的 Ingress 操控器有必要要具有该根底才干(能够理解为 Nginx 供给数据面的才干,Kruise-Rollout 供给管控面的才干)。
在该装备下,假定有副本数量为 10 的 Deployment,则其将被区分为三批进行发布,详细行为如下:
- 第一批合计有 1 个新版别 Pod,9 个旧版别Pod, 而且指定满意 UserAgent=iOS 这一匹配规矩的用户流量才会打入新版别 Pod,其余流量会均匀打入剩下 9 个旧版别 Pod;
- 第二批合计有 5 个新版别 Pod,5 个旧版别Pod,而且取消流量匹配规矩,流量直接悉数走负载均衡战略;
- 第三批合计有 10个新版别 Pod,0 个旧版别Pod,而且取消流量匹配规矩,流量直接悉数走负载均衡战略;
新特性三:依据Lua脚本的Ingress流量扩展计划
云原生技术发展到今天,云原生网关也呈现出百家争鸣的状况,除了 Kubernetes 原生供给的 Nginx Ingress 以及 Gateway API之外,也存在着十分多的 Network Provider 计划,比方阿里云 ALB、MSE、ASM;社区的 Istio、Kong、Apisix ,甚至是许多公司是自研网关计划和协议等等。Kruise Rollout 规划之初就考虑过百家争鸣的云原生网关应该怎么支撑,惯例的硬编码的方法既费时吃力,也不便利不同公司的同学对接运用和维护。
最终,Kruise Rollout 选择依据Lua脚本的方法,让用户以插件化的方法支撑更多类型的网关协议(此版别只支撑依据 Ingress 的扩展协议,其它自定义资源协议将在下个版别支撑),Kruise Rollout 完结一些通用部分的才干,而不同 NetWork Provider 的详细完结则由 Lua 脚原本处理,这样针对不同的完结,只需求编写对应的 Lua 脚本即可,可参阅:**Nginx与Alb Lua脚本示例 [ 3] **。为了便利大家依据自己的需求编写自己的Lua脚本,下面针对 Nginx Ingress 解读一下lua脚本(对应的 Rollout 装备能够参阅 新特性二),该脚本能够放置于特定目录或特定ConfigMap:
-- 由于 Ingress 灰度发布协议都是依据 Annotations 来完结的,所以此脚本的一切操作
-- 都是修正 Annotations 到方针状况,kruise rollout会将此 annotations patch 到
-- ingress canary 资源傍边
annotations = {}
-- obj.annotations 是Ingress.Annotations 此句不需求改变,固定即可
if ( obj.annotations )
then
annotations = obj.annotations
end
-- 这是 nginx 灰度发布协议的规范,其它的完结也能够依据自己的实际情况调整
annotations["nginx.ingress.kubernetes.io/canary"] = "true"
-- nginx 的灰度发布协议改变主要是下面这些改变,为了简化多个批次间来回切换的复杂度,每次
-- 都先将这些 annotations 置空
annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = nil
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = nil
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = nil
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = nil
annotations["nginx.ingress.kubernetes.io/canary-weight"] = nil
-- obj.weight 是 rollout.spec.strategy.canary.steps[x].weight
-- 代表当前批次的灰度百分比,当不设置时为 ‘-1’(lua脚本不支撑nil,所以用‘-1’表明),
-- 所以假如不是 ‘-1’,需求将 obj.weight 设置到 annotations 中
if ( obj.weight ~= "-1" )
then
annotations["nginx.ingress.kubernetes.io/canary-weight"] = obj.weight
end
-- obj.matches 是 rollout.spec.strategy.canary.steps[x].matches(数据结构一样),
-- 当没有设置时表明此step不需求进行 A/B Testing 发布,直接回来即可
if ( not obj.matches )
then
return annotations
end
-- A/B Testing发布,遍历 matches ,将 matches 设置到 annotations 中
-- 留意:nginx 并不支撑多个header,所以这儿并不需求真正的遍历,默许只取第一个数组
for _,match in ipairs(obj.matches) do
-- 留意 lua 脚本傍边数组是从下标 ‘1’ 开端
local header = match.headers[1]
-- cookie
if ( header.name == "canary-by-cookie" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = header.value
-- header
else
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = header.name
-- 是否是“正则”
if ( header.type == "RegularExpression" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = header.value
end
end
end
-- must be return annotations
return annotations
注:此版别只针对 Ingress 资源来完结的,面临 Apisix、Kong 等其它自定义资源(CRD)将在下一个版别支撑。**相关 PR [ 4] **现已提交 Github,欢迎大家一起评论。
未来规划
- 更多网关协议支撑:Kruise Rollout 现在是以 Lua 脚本插件化的方法支撑多类型的网关协议,咱们后续会要点加大这方面的投入,但面临百家争鸣的协议类型,单靠社区 Maintainer 的单薄力量还远远不够,期望更多的社区小伙伴参加咱们,一起来不断完善这方面的内容。
- 更完善的发布系统:为支撑包含灰度、告警、可观测、自动回滚、无人值守等在内的较为完整的发布系统,需求持续建造一些发布发布时的 Hook 调用与 Prometheus Metrics Analysis 等相关才干,这块咱们现在正在与 KubeVela 社区严密协作,经过 KubeVela 现有的 Workflow 系统集成来补偿现在这些才干的缺失,至于后续是否需求将这些才干做到 Kruise Rollout 之中,咱们也期望聆听更多的社区意见,欢迎大家一块评论沟通。
社区参加
十分欢迎你经过 Github/Slack/钉钉/微信 等方法参加咱们来参加 OpenKruise 开源社区。
你是否现已有一些期望与咱们社区沟通的内容呢?
能够在咱们的**社区双周会 [ 5] **上分享你的声音,或经过以下渠道参加评论:
- 参加社区**Slack channel [ 6] **(English)
- 参加社区钉钉群:搜索群号 23330762 (Chinese)
- 参加社区微信群(新):添加用户 openkruise 并让机器人拉你入群 (Chinese)
相关链接
[1]flagger
github.com/fluxcd/flag…
[2]Argo-Rollout
github.com/argoproj/ar…
[3] Nginx与Alb Lua脚本示例*github.com/openkruise/…*
[4] 相关 PR
github.com/openkruise/…
[5] 社区双周会
shimo.im/docs/gXqmeQ…
[6] Slack channel
kubernetes.slack.com/?redir=%2Fa…
戳这儿,查看 OpenKruise 项目官方主页与文档