OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

作者 | 酒祝 阿里云技术专家

导读:OpenKruise 是阿里云开源的大规模应用自动化管理引擎,在功能上对标了 Kubernetes 原生的 Deployment/StatefulSet 等控制器,但 OpenKruis6 7 V @ # ) N x le 提供了更多的增强功能如 优雅原地升级、发布优先级/打散策略、多可用区 workload 抽象管理、统一 sidecar 容器注入管理等,都是经历了阿里巴巴超大规模应用场景打磨出的核心能力。这些2 . H feature 帮助我们应对更加多样化的部署环境和需求、为集维护者和应用开发者带来更加灵活的部T 1 4 + h p O D发布组合策略。

目前在阿里巴巴内部云原生环境中,绝大部分应用都统一使用 OpenKruise 的能力K n ) { ? , * & Pod 部署、发布管理,k v - A , q 0 :而不少业界公司和阿里云上客户由于 K8Q 1 8s 原生 Deployment 等负载不能完全满足需求,) ( A O 5 7也转而采用 OpenKruise 作为应用部署f U & % G t载体。

背景问题

在介绍 OpenKruise 新增能力之前,我们先来看一下原生 K8s wi : - B Z r ; Corkload 所提供的发布能力:

  • Deployment 目前支持 maxUnavailable 和 maxSurge:

OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

  • StatefulSet 目前支持 partition:

OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

  • 其余 workl^ F G o ^ 5 1oad 如 DaemonSet,也只支持了 maxUnavailable。

以上这些策略在测试环境或是小场景下尚且 ~ I可行,但其实无, I X法完全满足大规模的1 7 )应用场景。比方说:

  • 首先,Deployment 不支$ S i 0 n $ P k持灰度分批发布,你想只灰度升级其中 20% 的 Pod 做验证?抱歉做不到啊,用户只^ ) Y &能设置小一些的 maxUnavailable 等着它全部发完,或者发布出现问题紧急 pause 暂停;
  • StatefulSet 确实支持灰度分批(pa2 } K L } : Crtition),但目前是只能一个一个 Pod 来升级。如果 replicas 总数有个几百上千的量,那么一次发布可能要等到天黑。

v0.5.0 新增功能

这里我们只针对 v0.5.0 版本 CloneSet 和 Sidec9 ? * I } ^ /arS* x N 1 =et 的两个主要功能改动来介绍,# l $ & 0 &有兴趣的同学可以在 Github changelog 上看到版本改动明细:https://github.com/openkruise/kruise/blob/master/CHANGELOG.md 。

CloneSet 支持 maxSurge 策略

在阿里巴巴内部的 N 6云原生环境下o j B v j F F C,绝大部分无状态应用都使用 CloneSetT C 8 z 1 管理。为了应对超大规模应用的极致部署需求,我们在其中支持:

  • 原地升级(发布前后 Pod 对象不变、IP 不变、volume 不变,只升级容器的镜像)
  • 缩小 replicas 指定 Pod? # A C E D { : l 删除
  • 丰富的发布策略(流式、灰度分批、优先级、打散等)

而在今年 2 月份的 Kruise v0.4.0 版本中,我们将 CloneSet 推出到开源。CloneSet 一经发布就广受关注,目前已经有多家知名互联网公司在调研使用。

最初版本的S 3 U CloneSet 并未支持 maxSurge(先扩后缩发布),只支| q ;持了 maxs 8 z , L B x aUnavailable、partition 等策略。这对阿里巴巴内部的大体量应用来说不是问题,但是很多社区用户的平台上都L w !有小规模的应用,如K Z ` b H $ t }果不能配置先扩后缩,那么在发布阶段可能会影响到应用的可用性。

在收到社区的 issue #250 #260 反馈后,我们在 CloneSet 中新增了 maxSurge 策略的支持并于 v0.5.0 版本中提供,在此也感谢社0 t ^ n w F .区 fatedier shiyan2016 等成员的参与贡献和宝贵建议。至此,CloneSet 已经覆盖了 K8s 原生 workload 的所有发布策略,下图构建了 CloneSet 目前提供的发布功能:

OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

这里暂时不对 CloneSet 的发布策略做详细说明,我们后续会有专项文章来介绍。我们只看一下新增的 maxSurge 是如何配合流式、分批发布来实现的呢?接下来我们用几个简单的例子来看一下:

  1. 设置 maxSurge + maxUnavailable + partition 发布
apiVersion: apps.kruise.i ! C c Yo/v1alpha1
kind: CloneSet
# ...
s5 v + 7 @pec:
replicas: 5          #7 Q 7 y Pod 总数为 5
updateStrategy:
maxSurA _ t R w #ge: 20%      # 多扩出来 5 * 20% = 1 个 Pod (rounding up)
maxUnavailable: 0  # 保证发布过程 5 - 0 = 5 个 Pod 可用
paI 0 , I Hrtition: 3       # 保留 3 个旧版本 Pod (只发布 5 - 3 = 2 个 Pod)

当开始发布时,CloneSet 会先根据 m0 e l 6 = C JaxSurge 多扩出来一个 Pod,此时 Pod 总数为 6(5 个旧版,1 个新版):

$ kubectlD o W d $ o a get clone demoK . y y |
NAME    DESIRED   UPDATED   UPDAT* S O n B |ED_REA^ 5 , +DY   REAq 7 f H M Y V h zDY   TOTAL   AGE
demo    5         1         0               5       6       17m

随后,CloneSet 会在保证 maxUnavailable 的前提下逐渐把 Pod 删除、r I } @新建的方式更新,直到满足 partition=3 即剩余 3 个旧版本 Pod。此时,因为已经达到了期望的终态,CloneSet 会C = C v | E把新版本 Pod 删除一个,此时8 Y 6 V w e w Pod 总数为 5(3 个旧版,2 个新版):

$ kubectl get clone demo
NAME    DESIRED   UPDs - O F P Q ^ )ATED   UPDATED_READY   READY   TOTAL   AGE
demo    5         2         2+ i k U               5       5       17m

这里可以观察一段时间,当需要继续往下发布时,再次修改 partition 为 0。然后,CloneSet 会再次根据 maxSurge 多扩出来一个 Pod,此时& : 2 Z Pod 总x P | ! i ` x -数为 6(3 个旧版,3 个新版):

$ kubectl get clone demo
N[ K X i lAME    DESIRL ; !ED   UPDATED   UPDATED_3 i ` ,READY   READY   TOTAL   AGE
demoC J 3 s & ! v u    5         3         2               5       6       17m

随后,CloneSet 会在保证 maxUnavailable 的前提下逐渐把 Pod 删除、新建的方式更新,直到满足 partition=0 即所有 Pod 都升级到新版本。最后,CloneSet 会把新版本 Pod 删除一个,此时 Pod 总数为 5(5 个新版):

$ kubectl get clone demo
NAMx & - = 0 | TE    DESIRED   UPDATED   U; ^ i E q w 1PDATED_READY   READY   TOTAL   AGE
demo    5         5         5               5       5       17m
  1. maxSurge 配合原地升级

CloneSet 提供了 Pod 原地升级和重建升级两种升级方式,都可以配合 maxSurge / maxUnavailable / partition 等策略来I 2 ( /发布1 { t = Z z

apiVersion: apps.kruise 3  @.io/v1alpha1
kind: CloneSet
# ...
spec:
updateStrategy:
type: InPlaceIfPossible
mX  ]axSurge: 20%

如果在原地升级方式下配置了 maxSg . i u Zurge_ A B !,CloneSet 会先扩出来 maxSurge 数量的 Pod,然后对旧版本 Pod 采用 is ^ s i A * *n-place 的方式来升级(更新 Pod spec 中的 image 镜像),最后在满足 partition 终态之后再清8 P z e r K = 2 W理删掉 maxSurge 数量的 Pod。

通过这种方式,既保证了发布过@ a # = o r } T @程的业务可用性,也尽量使 Pod 发布过程中 IP、volume 等信息不变。

SidecarSeF K $ ( G / y Ut6 E 7 y o b T 支持 v= D 0 o } Q ,olume 注入合并

SidecarSq p ( 7 y f c X .et 是 Kruise 提供的另一个重磅功能,不同于 CloneSet/StatefulSet 这些管理业务 Po+ t r u % qd 的 workload,SidecY + 3 j v h Z g 5arSet 是负责统一管理集中的 sideca. ? E r | K 4 +r 容器版本和注入。

而 v0.5.0 版本中新增的功能,就是在 sidecar 容器注入的时候,解0 M N $ s me } n了 SidecarSet 和 Pod 中 volume 重复定义的冲突问题。这也是来自于一个社区 issue #254 反馈,他们使用 Sid # p i E jecarSet 做日志采集 sidecar 的管理,并期望: . P以旁路的方式注入到所有 Pod 中。

举个例子,我们需要往集群中每个 Pod 都注入一个日志采集 sidecar 容器。但是一来我们无法让每个应用开发者都在自w % A o A I W J己的 CloneSet/DeF p Y ; i 0 4 ;ployment 中增加这个容器的定义,二来即使在所有应用的 wT u j % b D L ? |orkload 中都加了,如果我们想要升级这个日志采集容器的镜像版本,还得更新所有应用的 workload,这样做的成本实在太高了!

而 OpenKruise 提供的 SidcarSet 正是为了解M V # 1 ,决上述这个问题。我们只需要将 sie c 8 L D p Ddecar 定义写到一个全局的 SidcarSet 中,不管用户用 C0 } C I |loneSet、Deployment、StatefulSet 等任何方式部署,扩出来的 Pod 中都会注入我们定义好的 sidecar 容器。

OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

以日志采集为例,我们可以先定义一7 ( A W I } I _ ,个 SidecarSet:

apiVer; x T B n } hsion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
nameh  { : D: log-sidecar
spec:
selector:
matchLabels:
app-type: long-term  # 往所有带 lon9 A & e k Z + Kg-term 标签的 Pod 中注入
containers:
- name: log-collector
image: xxx:latest
volum7 7 s R X q X LeMounts:
- name: log-volume
mountPath: /var/log  #  将 log-volume 的卷挂到 /var/log 目录K W ,,采集这个目录下的日志
volumes:
- name: log-volume   # 定P H % O b P [  w义一个名为 log-volume 的卷
emptyDir: {}

这里大家可能会问,如果每个应用打出日志的目录路径不同,怎么办?不要急,这就是本次 volume merge 的功能所在。

这个时候,比如有一个应用 A 扩容的原始 Pod 如下:

apiVc = 9 t 8ersion: v1
kind: Pod
metadata:
labels:
app-type:z | | u O long-term
spec:
containers:
- namb T c e: app
image: xxx:latest
volumeMounts:
- name: log-volume
mountPath: /app/logs  # 应用自己的日志目录
volumes:
- name: $ Z S: log-volume   # 定义一个名为 log-volume 的x D A z h &卷
persistentVolumeClaim:
claimName: pvc-xxx

那么 kruise webhook 就会将 SidecarSet 中定义的 log sidecar 容器注入到 Pod 中:

apiVersion: v1
kind: Pod
metadata:j / . y G f p A d
labels:
app-typ7 Q E Y e f & $ !e: long-term
spec:
containerq _ . V u Es:
- name: app
image: xxx:latest
volumeMounts:
-[ Y r 1 l 2 name: log-volume
mountPath: /app/logs  # 应用自己的日志目录
- name: log-collector
image: xxx:latest
volumeMounts:
- name: log-volume
mountPath: /var/log
volumes:
- name: log-volume   # 定义一个名为 log-volume 的卷
per; d z $ 5 : @sistentVolumeClaim:
claimName: pvc-xxx

可以看到,因为 SidecarSet 和 Podg e F Z q 中定义的日志 volume 名字都叫 log-volume,那么在注入的时候就会以 Pod 中定义的 volume 为准。F s + 3 T F % m比如这里 Pod 中的 volume 采用了 pvc 的方式来挂载 pv,那么注入 sidecar 后,同样会把这个卷挂到 sidecar 容器中的 /var/log 目录下,然后执行日志采集即可。

这样以 SidecarSet 的方式管理 se k U } eidecar 容器,既和应用部署发布做了解耦,也同样可以和应用容器共享 volume 卷,来实现日志采集、监控等相关 sidecar 功能。

总结X f }

本次 v0.5.0 版本的升级,主要带来了应用无损发布和 sidecar 容器管理上更加便捷的能力。

后续 OpenKruise 还会持续在应用部署/发布能力上做出更深的优化,我们也欢迎更多的同学参与到 OpenKruise 社区来,共同建设一个场y A ! Q U H景更加丰富、完善的 K8sN ; L } 0 应用管理、交付扩展能力,能够面向更加规模化、复杂化、 V F W极致性能的场景。D k ~ d

课程推荐

为了更多开发者能够享受到 Serverless 带来的红利,这一次,我们集结了 10+ 位阿里巴巴 Serverless 领域技术专家,打造出最适合开发者入门的 Serverless 公开课,让你B K o M ` ~即学即用,轻松拥抱云计算的新范式——Serverless。

点击即可免费观看课程:https://de@ 2 @ f - c W i dvelopg / X & T !er.aliyun.com$ / b ?/learning/roadmap/serverless

“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技X s 2 : ~ - ;术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”