前言
OpenKruise 是阿里云开源的大规模应用自动化管理引擎,在功能上对标了 Kubernetes 原生的 Deployment/StatefulSet 等控制器,但 OpenKruise 提供了更多的增强功能如 优雅原地升级、发布优先级/打散策略、多可用区workload抽象管理、统一 sidecar 容器注入管理等,都是经历了阿里巴巴超大规模应用场景打磨出的核心能力。这些 feature 帮助我们应对更加多样化的部署环境和需求、为集群维护者和应用开发者带来更加灵活的部署发布组合策略。
目前在阿里巴巴内部云原生环境中,应用全部统一使用 OpenKruise 的能力做 Pod 部署、发布管理,而不少业界公司和阿里云上客户由于K8s原生 Deployment 等负载不能完全满足需求,也转而采用 OpenKruise 作为应用部署载体。我们希望 OpenKruise 能让每一位 Kubernetes 开发者和阿里云上的用户都能便捷地使用上阿里巴巴内部云原生应用所统一使用的部署发布能力!
(附:OpenKruise 在阿里巴巴的应用参考文章 https://mp.weixin.qq.com/s/DxB1Cd07ZIYf2QYYAESseg )
新版本概览
Kruise 在 2020.11.16 发布了最新的 v0.7.0 版本,包括了一些主体功能和优化迭代。本文以下对新版本做一个整体的概览介绍。
1. Advanced StatefulSet
Advanced StatefulSet 基于原生 StatefulSet 上增强了发布能力,比如 maxUnavailable 并行发布、原地升级等。(官网文档:https://openkruise.io/zh-cn/docs/advanced_statefulset.html )
1.1 OpenKruise 中首个进入 v1beta1 版本
过去 OpenKruise 中提供的自定义 workload 均是 v1alpha1 版本,随着阿里巴巴内部和众多社区用户的大规模使用,我们会逐渐将稳定的能力升级到更高的版本。本次 Advanced StatefulSet 是首个进入 v1beta1 的 CRD,后续 CloneSet、SidecarSet 等资源也会逐渐跟进。
那么对于过去使用 v1alpha1 版本 Advanced StatefulSet 的用户,升级到 v1beta1 版本是否会有问题呢?这里明确地告诉大家,是没有风险的。不仅存量的 Advanced StatefulSet 对象会自动转到 v1beta1 版本,而且用户还可以继续沿用 v1alpha1 的接口和客户端来操作新版本的对象。
首先看图中新版本 Advanced StatefulSet 的 CRD 定义:
- 设置了 conversion 字段,其中指定通过 kruise-webhook-service 来提供 convert 服务,这个 service 后端挂载的其实就是 kruise-controller-manager 节点( Kruise 的 MutatingWebhookConfiguration/ValidationWebhookConfiguration 中配置的也是这个 service)
- versions 列表中目前有 v1alpha1 和 v1beta1 两个版本,其中后者的 storage 设置为 true,表示在 etcd 中存储的是这个版本
再来看图中的 conversion 链路:
- 当用户直接使用 v1beta1 接口操作 Advanced StatefulSet,不需要 conversion 转换,apiserver 直接和 etcd 交互
- 如果用户使用老版本的 v1alpha1 接口操作 Advanced StatefulSet:
-
- 写操作:apiserver 会先调用 webhook 将用户写的 v1alpha1 对象转为 v1beta1,并写入 etcd
- 读操作,apiserver 将来自于 etcd 的 v1beta1 对象通过 webhook 转为 v1alpha1,再返回给用户
多版本 conversion 的逻辑有兴趣的同学可以阅读源码:https://github.com/openkruise/kruise/blob/master/apis/apps/v1alpha1/statefulset_conversion.go
1.2 Ordinal 序号保留(跳过)
通常来说,不管是社区原生 StatefulSet 或是 Advanced StatefulSet,扩容出来的 Pod 以及 PVC 都是连续序号。比方说对于一个 replicas=4 的 StatefulSet,那么创建出来的 Pod 序号则是 [0,1,2,3]
。
但有些情况下,用户需要指定删除一个序号的 Pod,并希望 StatefulSet 暂时跳过这个序号。这种需求在使用 Local PV 的场景下尤为突出:当一些节点出现故障的时候如果只是删除原 Pod,那么重建出相同序号的 Pod 复用了原有的 PVC/PV,还是会调度到原来的节点上。
从 Advanced StatefulSet 的 v1beta1 版本开始(对应 Kruise 版本 >= v0.7.0),我们提供了序号保留功能:
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
replicas: 4
reserveOrdinals:
- 1
通过在 reserveOrdinals 字段中写入需要保留的序号,Advanced StatefulSet 会自动跳过创建这些序号的 Pod。如果 Pod 已经存在,则会被删除。 注意,spec.replicas
是期望运行的 Pod 数量,spec.reserveOrdinals
是要跳过的序号。
因此,对于一个 replicas=4, reserveOrdinals=[1] 的 Advanced StatefulSet,实际运行的 Pod 序号为 [0,2,3,4]
。
- 如果要把 Pod-3 做迁移并保留序号,则把 3 追加到 reserveOrdinals 列表中。控制器会把 Pod-3 删除并创建 Pod-5(此时运行中 Pod 为
[0,2,4,5]
)。 - 如果只想删除 Pod-3,则把 3 追加到 reserveOrdinals 列表并同时把 replicas 减一修改为 3。控制器会把 Pod-3 删除(此时运行中 Pod 为
[0,2,4]
)。
2. CloneSet
CloneSet 控制器提供了高效管理无状态应用的能力,它可以对标原生的 Deployment,但 CloneSet 提供了很多增强功能。(官网文档:http://openkruise.io/zh-cn/docs/cloneset.html )
2.1 partition 支持百分比
CloneSet 中支持使用 partition 字段控制发布时的灰度数量,过去版本中这个字段只能设置为一个绝对值,而从 v0.7.0 开始可以设置为百分比。它的语义是 保留旧版本 Pod 的数量或百分比,默认为 0。
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
# ...
updateStrategy:
partition: 80% # 表示只将 20% 比例的 Pod 升级为新版本;或者也可以设置为保留旧版本数量的绝对值
如果在发布过程中设置了 partition
:
- 如果是数字,控制器会将
(replicas - partition)
数量的 Pod 更新到最新版本。 - 如果是百分比,控制器会将
(replicas * (100% - partition))
数量的 Pod 更新到最新版本。
2.2 其他优化点
解决了过去一些边缘场景下的 bug(部分要感谢社区同学们的反馈和贡献):
- 不满足 selector 匹配条件的 Pod 自动去除 owner reference
- 解决 resourceVersionExpectation 偶发的 race condition
- 解决使用了 gracePeriodSeconds 优雅原地升级时连续升级的版本覆盖问题
3. AdvancedCronJob(新增控制器)
AdvancedCronJob 是 v0.7.0 中新增的控制器,它一个 CronJob 的扩展版本,感谢来自 Spectro Cloud 的 rishi-anand 的贡献!
原生 CronJob 只支持创建 Job 执行任务,而 AdvancedCronJob 允许用户设置多种不同类型的 template,即用户可以配置 schedule 规则周期性创建 Job 或 BroadcastJob 来执行任务(后者可以分发 Job 到所有或特定 node 上执行任务)。
apiVersion: apps.kruise.io/v1alpha1
kind: AdvancedCronJob
spec:
template:
# Option 1: use jobTemplate, which is equivalent to original CronJob
jobTemplate:
# ...
# Option 2: use broadcastJobTemplate, which will create a BroadcastJob object when cron schedule triggers
broadcastJobTemplate:
# ...
# Options 3(future): ...
- jobTemplate:与原生 CronJob 一样创建 Job 执行任务
- broadcastJobTemplate:周期性创建 BroadcastJob 执行任务
4. Webhook 自运维控制器
Kruise 运行的 kruise-controller-manager 组件,其中包含了多个 controller 和 webhook。
了解 webhook 的同学应该知道,它需要生成一套完整的 TLS cert 证书,webhook server 端的 HTTPS 服务启动时使用这个证书,同时要把 ca 证书写到 MutatingWebhookConfiguration、ValidatingWebhookConfiguration、CRD conversion 的 caBundle 中。
因此,对于如何自动生成证书、配置到上述 configuration 资源中,以及如果 configuration 被重置后如何重新写入,都是当前写 webhook 会遇到的运维难题。
Kruise 最新版本中实现了一个 webhook controller,这个控制器支持对 Kruise 自身的 TLS certs 以及相关配置资源做自运维。即 自动生成证书 -> 存储到secret -> 写到本地供 HTTPS 服务启动使用 -> 将 ca cert 写入 MutatingWebhookConfiguration/ValidatingWebhookConfiguration/CRD conversion,并持续 list watch 这些资源,一旦发生变化,重新刷入 ca 证书。
有兴趣的同学可以看源码:https://github.com/openkruise/kruise/blob/master/pkg/webhook/util/controller/webhook_controller.go
后续我们也会将这部分功能抽出到一个公共的仓库中,大家在编写 webhook 的时候可以很方便地复用这套 webhook 自运维能力。
总结
后续 OpenKruise 还会持续在应用自动化上做出更深的优化,本月底会开放 OpenKruise 下一步的 Roadmap 规划,我们将不再局限于 workload 应用管理能力,而会扩展到更多风险防控、operator 增强等领域。
我们也欢迎每一位云原生爱好者来共同参与 OpenKruise 的建设。与其他一些开源项目不同,OpenKruise 并不是阿里内部代码的复刻;恰恰相反,OpenKruise Github 仓库是阿里内部代码库的 upstream。因此,每一行你贡献的代码,都将运行在阿里内部的所有 Kubernetes 集群中、都将共同支撑了阿里巴巴全球顶尖规模的云原生应用场景!