开源之夏2021 - KubeVela 项目申请书
本文是我在「开源软件供应链点亮计划 2021」活动中的项目申请书,申请的项目是阿里云 KubeVela 的「实现 KubeVela 的 StatefulSet 和 AdvancedSatefulSet Rollout Plugin Controller」。
背景:KubeVela 的 Rollout 的主要功能是在创建或者更新 Application 时,对工作的 Pod 进行滚动升级。防止一次性地更新全部的工作负载 Pod,导致服务的中断。现在 Vela 已经对 Deployment 和 CloneSet 进行了完整的支持。
任务:实现 StatefulSet 和 AdvancedSatefulSet 的 Rollout Plugin 接口。包括两部分的 Controller:Scale Controller 和 Rollout Controller。
项目背景
KubeVela 是一个云原生平台构建引擎,提供了云原生应用管理的能力,其能力之一就是应用的滚动发布。这一小节主要介绍应用滚动发布功能的背景。
自定义资源和 Controller 的实现
KubeVela 提供了 Application、AppDeployment 和 ApplicationConfiguration 等一系列自定义资源。通过 Operator 模式,KubeVela 可以为这些资源提供 Controller 的实现。在具体的实现上,KubeVela 使用了 Kubebuilder 来实现自定义资源和 Controller,其底层依赖于 controller-runtime 库。
在 controller-runtime 库中,Controller 由 Manager 管理,依赖 Reconciler 实现。在某个 Controller 启动后,controller-runtime 会生成一个工作队列,然后启动用户实现的 Reconciler,并监听 Controller 管理的资源的相关事件(Add / Update / Delete)。
在自定义资源被创建、修改或删除时,需要向工作队列中添加其一个 Request 对象(包含 Namespace 和 Name 属性),但不提供其余的事件相关信息。
Reconciler 会尝试从工作队列中获取 Request 对象。如果工作队列为空,则阻塞;否则,对 Request 对象 做进一步的处理。
Request 对象的处理依赖于用户在创建 Controller 时提供的 Reconciler。每个 Reconciler 至少需要提供一个 Reconcile 函数,它接收一个 Request 对象,并在返回结果中指示工作队列接下来对该 Request 对象的处理方式。由于 Request 对象中只包含资源的 Namespace 和 Name 属性,所以 Reconciler 需要自行与集群交互,查询相关资源的状态。
根据 Reconcile 函数的返回结果进行判断,如果 Reconcile 流程出错或者需要重新执行,则需要将 Request 对象放回到队列中;而如果 Reconcile 流程执行完成,则在队列中删除对应的 Request 对象。
进一步的分析可见:自定义 Kubernetes Controller。
Rollout Plan
在默认情况下,KubeVela 会对应用执行原地发布,也就是进行全量的切换。如果用户需要进行滚动发布,则要提供 RolloutPlan 结构,其属性包括:
| 属性 | 类型 | 含义 |
|---|---|---|
| RolloutStrategy | 字符串 | 滚动发布的策略 |
| TargetSize | 整数 | 目标资源的大小 |
| NumBatches | 整数 | Batch 的数量(也就是滚动的次数) |
| RolloutBatches | RolloutBatch 结构数组 | 各个 Batch 的数量或百分比分布 |
| BatchPartition | 整数 | 滚动的次数上限 |
| Paused | 布尔值 | 是否暂停滚动 |
| RolloutWebhooks | RolloutWebhook 结构数组 | 用户提供的 Webhook 列表(用于接收滚动发布相关的事件信息) |
| CanaryMetric | CanaryMetric 结构数组 | 用于指标的监控 |
用户可在 Application、RolloutTrait 或 AppRollout 中提供 RolloutPlan。在底层,滚动发布都是通过 AppRollout 的 API 来完成的。
滚动发布相关组件
与滚动发布相关的部分组件如下图:

其中,Application Controller 依赖于 AppHandler 处理滚动发布;AppHandler 依赖于 ApplicationRollout Controller 的控制逻辑完成滚动发布的具体实现;ApplicationRollout Controller 依赖于 RolloutPlan Controller 执行 RolloutPlan;RolloutPlan Controller 依赖于 Workload Controller 接口完成具体 Workload 的滚动发布;Workload Controller 的具体实现有四个,包括 Deployment Scale Controller、Deployment Rollout Controller、CloneSet Scale Controller 和 CloneSet Rollout Controller。
另外,由于 Application Controller 和 ApplicationRollout Controller 都注册到了 controller-runtime 的 Manager 中,所以它们的控制循环由 Manager 进行管理。
滚动发布相关流程
本小节将描述滚动发布的相关流程。受篇幅所限,此处仅列出关键点。
Application Controller 的控制流程如下:
-
将
Application解析成AppFile。 -
创建
AppHandler,并通过AppHandler生成应用的AppRevision、ApplicationConfiguration和相关组件。 -
如果
AppRevision是新创建的或者有更新,则应用组件对应的资源。 -
如果用户提供了
RolloutPlan,则通过AppHandler处理滚动发布,并根据返回的结果(Requeue / RequeueAfter)决定下一步的操作。
AppHandler 处理滚动发布的流程如下:
-
设置
TargetAppRevisionName,其值为最新AppRevision的名称。 -
设置
SourceAppRevisionName。如果最新AppRevision的 ID 为 1,说明Application是首次发布,则将SourceAppRevisionName设置为空,表示接下来要进行Scale操作;而如果最新AppRevision的 ID 大于 1,则说明之前已经创建过AppRevision,则将SourceAppRevisionName设置为上一个AppRevision的名称。 -
通过
SourceAppRevisionName、TargetAppRevisionName和RolloutPlan等信息创建AppRollout。 -
借助
ApplicationRollout Controller的控制逻辑处理AppRollout。
ApplicationRollout Controller 处理 AppRollout 的过程如下:
-
如果
Rollout已经执行结束,且SourceAppRevisionName和TargetAppRevisionName均无变化,则结束流程。 -
如果
SourceAppRevisionName非空,则通过它获取SourceAppRevision和SourceAppContext。 -
通过
TargetAppRevisionName获取TargetAppRevision和TargetAppContext。 -
如果
SourceAppRevisionName非空,则通过SourceAppRevision获取SourceWorkload,也就是旧AppRevision中组件对应的Workload。 -
通过
TargetAppRevisionName获取TargetWorkload,也就是新AppRevision中组件对应的Workload。 -
创建
RolloutPlan Controller,并传入SourceWorkload和TargetWorkload。通过其 Reconcile 过程,执行控制循环。
RolloutPlan Controller 执行滚动发布的流程如下:
-
根据
TargetWorkload的类型和SourceWorkload是否为空来选择Workload Controller。-
如果
TargetWorkload的类型为Deployment,则选择Deployment相关的Workload Controller。- 如果
SourceWorkload为空,说明需要执行Scale操作,选择Deployment Scale Controller;否则,说明需要执行Rollout操作,选择Deployment Rollout Controller。
- 如果
-
如果
TargetWorkload的类型为CloneSet,则选择CloneSet相关的Workload Controller。- 如果
SourceWorkload为空,说明需要执行Scale操作,选择CloneSet Scale Controller;否则,说明需要执行Rollout操作,选择CloneSet Rollout Controller。
- 如果
-
-
根据
RollingState,依赖Workload Controller来执行不同的操作。(在正常情况下,RollingState的状态变化为LocatingTargetApp->VerifyingSpec->Initializing->RollingInBatches->Finalising->RolloutSucceed。)-
如果
RollingState为VerifyingSpec,说明当前阶段需要进行滚动发布前的验证,检查资源能否根据RolloutPlan进行升级,此处需要调用Workload Controller的VerifySpec函数。 -
如果
RollingState为Initializing,说明当前阶段需要进行滚动发布前的初始化,此处需要调用Workload Controller的Initialize函数。 -
如果
RollingState为RollingInBatches,则正式进入滚动发布阶段。这一阶段会包含多种状态,由BatchRollingState表示,后续执行的操作依赖于这个状态,直到完成所有 Batch。(在正常情况下,BatchRollingState的状态变化为BatchInitializing->BatchInRolling->BatchVerifying->BatchFinalizing->BatchReady。当RollingState被设置为RollingInBatches时,RollingState也被设置为BatchInitializing。)-
如果
BatchRollingState为BatchInitializing,则在执行当前 Batch 之前进行初始化。 -
如果
BatchRollingState为BatchInRolling,则调用Workload Controller的RolloutOneBatchPods函数,根据RolloutPlan设置当前 Batch 的任务。 -
如果
BatchRollingState为BatchVerifying,则调用Workload Controller的CheckOneBatchPods函数,检查当前 Batch 的任务是否已经执行完成。 -
如果
BatchRollingState为BatchFinalizing,则调用Workload Controller的FinalizeOneBatch函数,在完成 Batch 任务之后进行最后的检查,以确保滚动发布符合RolloutPlan的设定。- 如果检查结果为正确,则检查当前完成的 Batch 是不是最后一个 Batch。如果是,表明滚动升级完成,此时将
RollingState设置为FinalisingState;否则,说明仍有 Batch 需要执行。
- 如果检查结果为正确,则检查当前完成的 Batch 是不是最后一个 Batch。如果是,表明滚动升级完成,此时将
-
如果
BatchRollingState为BatchReadyState,则尝试跳转到下一个 Batch 的任务。如果跳转成功,BatchRollingState会被设置为BatchInitializing,继续处理下一个 Batch。
-
-
如果
RollingState为FinalisingState,则说明所有 Batch 任务都已经执行完成,此时调用Workload Controller的Finalize函数来完成最后的状态处理。 -
如果
RollingState为RolloutSucceed或RolloutFailed,则不需要进一步的操作。
-
项目的意义
如上文所述,KubeVela 提供了对于 Deployment 和 CloneSet 两种资源的 Workload Controller 实现,支持了 Deployment 和 CloneSet 的滚动发布。作为一个具有高扩展性的云原生平台构建引擎,支持多种 Workload 的滚动发布是非常有必要的。因此,本项目的目标就是在 KubeVela 中支持 StatefulSet 和 AdvancedSatefulSet 两种 Workload 的滚动发布。
项目方案
如前所述,每种 Workload 具有 Scale 和 Rollout 两种操作。其中,Scale 操作表示单个版本的滚动发布,Rollout 表示两个版本之间的滚动升级。为了支持 StatefulSet 和 AdvancedSatefulSet 两种 Workload 的滚动发布,我们需要提供四个 Workload Controller 的实现:
-
StatefulSet Scale Controller -
StatefulSet Rollout Controller -
AdvancedSatefulSet Scale Controller -
AdvancedSatefulSet Rollout Controller

这四个 Controller 都至少需要实现这些函数:
-
VerifySpec -
Initialize -
RolloutOneBatchPods -
CheckOneBatchPods -
FinalizeOneBatch -
Finalize
StatefulSet Scale Controller
-
VerifySpec函数:-
检查
RolloutPlan.TargetSize是否已经设置。如果是,则设置为RolloutStatus.RolloutTargetSize;否则,报错。 -
获取
StatefulSet的Spec.Replicas的属性(默认为 1),设置为RolloutStatus.RolloutOriginalSize。 -
调用公共函数
verifyBatchesWithScale,根据RolloutTargetSize和RolloutOriginalSize提前检查最后能否到达RolloutPlan设置的目标数量。如果不能,则检查不通过。 -
检查当前
StatefulSet是否在进行Scale或者更新操作。如果是,则检查不通过。 -
检查当前
StatefulSet是否已被某个Controller控制。如果是,则检查不通过。
-
-
Initialize函数:- 将
AppRollout添加到StatefulSet的Owner列表中。
- 将
-
RolloutOneBatchPods函数:- 计算执行当前 Batch 之后
StatefulSet的目标大小,并将StatefulSet的Spec.Replicas属性设置为该值。
- 计算执行当前 Batch 之后
-
CheckOneBatchPods函数:-
计算执行当前 Batch 之后的目标大小,检查当前 Batch 的
Scale任务是否已经完成。-
如果
Scale执行的是扩大操作,而且已经准备好的Pod的数量与当前 Batch 的 MaxUnavailable(最多允许多少个Pod不可用)之和大于或等于当前 Batch 的执行目标大小,则说明当前 Batch 的Scale任务已经完成。 -
如果
Scale执行的是缩小操作,而且已经准备好的Pod的数量小于或等于当前 Batch 的执行目标大小,则说明当前 Batch 的Scale任务已经完成。
-
-
-
FinalizeOneBatch函数:- 检查
RolloutStatus.UpgradedReplicas属性,确保执行当前 Batch 之后,已更新的Pod数量不会超过正常值。
- 检查
-
Finalize函数:- 在
StatefulSet的Owner列表中删除AppRollout。
- 在
StatefulSet Rollout Controller
-
VerifySpec函数:-
检查当前
SatefulSet是否在进行更新操作。如果是,则检查不通过。 -
根据
SatefulSet的Status.UpdateRevision属性判断SatefulSet是否有更新。如果无更新,则检查不通过。 -
调用公共函数
verifyBatchesWithRollout,提前检查RolloutPlan中的 Batch 设置是否合理。 -
检查当前
SatefulSet是否已被Controller控制。如果是,则检查不通过。
-
-
Initialize函数:-
将
AppRollout添加到SatefulSet的Owner列表中。 -
设置
SatefulSet的Spec.UpdateStrategy.Partition属性为当前SatefulSet的大小。
-
-
RolloutOneBatchPods函数:-
计算执行当前 Batch 之后
SatefulSet的目标大小。 -
设置
SatefulSet的Spec.UpdateStrategy.RollingUpdate.Partition属性为SatefulSet大小和本次 Batch 目标大小的差。
-
-
CheckOneBatchPods函数:- 如果
SatefulSet中已经准备好的Pod的数量与当前 Batch 的 MaxUnavailable(最多允许多少个Pod不可用)之和大于或等于当前 Batch 的执行目标大小,则说明当前 Batch 的Rollout任务已经完成。
- 如果
-
FinalizeOneBatch函数:- 检查
RolloutStatus.UpgradedReplicas属性,确保执行当前 Batch 之后,已更新的Pod数量不会超过正常值。
- 检查
-
Finalize函数:- 在
SatefulSet的Owner列表中删除AppRollout。
- 在
AdvancedSatefulSet Scale Controller
-
VerifySpec函数:-
检查
RolloutPlan.TargetSize是否已经设置。如果是,则设置为RolloutStatus.RolloutTargetSize;否则,报错。 -
获取
AdvancedSatefulSet的Spec.Replicas的属性(默认为 1),设置为RolloutStatus.RolloutOriginalSize。 -
调用公共函数
verifyBatchesWithScale,根据RolloutTargetSize和RolloutOriginalSize提前检查最后能否到达RolloutPlan设置的目标数量。如果不能,则检查不通过。 -
检查当前
AdvancedSatefulSet是否在进行Scale或者更新操作。如果是,则检查不通过。 -
检查当前
AdvancedSatefulSet是否已被某个Controller控制。如果是,则检查不通过。
-
-
Initialize函数:- 将
AppRollout添加到AdvancedSatefulSet的Owner列表中。
- 将
-
RolloutOneBatchPods函数:- 计算执行当前 Batch 之后
AdvancedSatefulSet的目标大小,并将AdvancedSatefulSet的Spec.Replicas属性设置为该值。
- 计算执行当前 Batch 之后
-
CheckOneBatchPods函数:-
计算执行当前 Batch 之后的目标大小,检查当前 Batch 的
Scale任务是否已经完成。-
如果
Scale执行的是扩大操作,而且已经准备好的Pod的数量与当前 Batch 的 MaxUnavailable(最多允许多少个Pod不可用)之和大于或等于当前 Batch 的执行目标大小,则说明当前 Batch 的Scale任务已经完成。 -
如果
Scale执行的是缩小操作,而且已经准备好的Pod的数量小于或等于当前 Batch 的执行目标大小,则说明当前 Batch 的Scale任务已经完成。
-
-
-
FinalizeOneBatch函数:- 检查
RolloutStatus.UpgradedReplicas属性,确保执行当前 Batch 之后,已更新的Pod数量不会超过正常值。
- 检查
-
Finalize函数:- 在
AdvancedSatefulSet的Owner列表中删除AppRollout。
- 在
AdvancedSatefulSet Rollout Controller
-
VerifySpec函数:-
检查当前
AdvancedSatefulSet是否在进行更新操作。如果是,则检查不通过。 -
根据
AdvancedSatefulSet的Status.UpdateRevision属性判断AdvancedSatefulSet是否有更新。如果无更新,则检查不通过。 -
调用公共函数
verifyBatchesWithRollout,提前检查RolloutPlan中的 Batch 设置是否合理。 -
检查当前
AdvancedSatefulSet是否已被Controller控制。如果是,则检查不通过。
-
-
Initialize函数:-
将
AppRollout添加到AdvancedSatefulSet的Owner列表中。 -
设置
AdvancedSatefulSet的Spec.UpdateStrategy.Partition属性为当前AdvancedSatefulSet的大小。
-
-
RolloutOneBatchPods函数:-
计算执行当前 Batch 之后
AdvancedSatefulSet的目标大小。 -
设置
AdvancedSatefulSet的Spec.UpdateStrategy.Partition属性为AdvancedSatefulSet大小和本次 Batch 目标大小的差。
-
-
CheckOneBatchPods函数:- 如果
AdvancedSatefulSet中已经准备好的Pod的数量与当前 Batch 的 MaxUnavailable(最多允许多少个Pod不可用)之和大于或等于当前 Batch 的执行目标大小,则说明当前 Batch 的Rollout任务已经完成。
- 如果
-
FinalizeOneBatch函数:- 检查
RolloutStatus.UpgradedReplicas属性,确保执行当前 Batch 之后,已更新的Pod数量不会超过正常值。
- 检查
-
Finalize函数:- 在
AdvancedSatefulSet的Owner列表中删除AppRollout。
- 在