OpenKruise CloneSet 滚动更新进度超时检测:progressDeadlineSeconds 字段设计与实现解析
云原生容器编排微服务运维【免费下载链接】kruiseAutomated management of large-scale applications on Kubernetes (incubating project under CNCF)项目地址https://gitcode.com/gh_mirrors/kr/kruise点击查看免费下载导读progressDeadlineSeconds是 Kubernetes Deployment 中用于控制滚动更新是否在规定时间内取得进展的经典字段一旦超时控制器会在.status.conditions中标记ProgressDeadlineExceeded条件帮助用户及时发现卡死的发布。本篇文章基于 OpenKruise 的 功能提案文档 及其在仓库中的完整落地实现讲解 CloneSet 如何引入这一字段包括与 Deployment 在语义上的关键差异partition 暂停时间不计入 deadline、API 字段与校验规则、Progressing条件的状态机、控制器源码级的超时判定与 requeue 机制以及对应的单元测试与 E2E 验证。读完本文你将掌握 CloneSet 发布进度超时检测的配置方法、运行原理和排查手段。背景与动机为什么 CloneSet 需要 progressDeadlineSeconds在原生 Kubernetes 中spec.progressDeadlineSeconds是 Deployment 的可选字段用于指定系统在判定 Deployment进展失败之前愿意等待的秒数。一旦超时Deployment 控制器会在.status.conditions中添加如下条件type: Progressing status: False reason: ProgressDeadlineExceeded该机制对发布管控非常有价值当新版本镜像拉取失败、Pod 持续 CrashLoop、探针不健康或配额不足时发布会长时间原地打转而progressDeadlineSeconds能把这种隐性故障显式暴露出来供上层监控和运维人员感知。CloneSet 是 OpenKruise 面向大规模应用的有状态工作负载支持原地升级、partition 分批发布、指定删除等能力其滚动更新同样存在卡住的风险因此 提案 提出为 CloneSet 增加同名字段。该功能已在仓库中落地参见 CHANGELOG.md对应 PR #2108在 v1alpha1 与 v1beta1 两个 API 版本中均可用。设计决策与 Deployment 的差异及社区取舍提案中明确指出由于 CloneSet 支持partition分批发布progressDeadlineSeconds在 CloneSet 中的行为不能简单照搬 Deployment。核心争议点在于CloneSet 因partition而暂停的时间是否应计入 progress deadline。提案给出了两种可能的解释重新定义语义progressDeadlineSeconds指 CloneSet 到达完成状态或因 partition 导致的暂停状态所花费的时间。此时暂停期间的时间不计入deadline。仅在未设置 partition 时生效一旦设置了 partitionprogressDeadlineSeconds就不适用或不起作用。社区讨论最终选择了第一种解释——即当 CloneSet 到达完成或暂停paused状态时需要重置计时起点。这一决策在 API 注释中也有明确体现cloneset_types.go 中写道ProgressDeadlineSeconds specifies the maximum time for the CloneSet to reach available or paused state due to partitioning. The controller will set a ProgressDeadlineExceeded condition when timeout occurs, while excluding paused state duration from the deadline calculation. This field is optional. If not set, the controller will not track progress deadlines or add the condition.翻译过来即该字段限定 CloneSet 到达可用available或因分区而暂停状态的最大时间超时后控制器写入ProgressDeadlineExceeded条件暂停时长从 deadline 计算中排除字段为可选不设置则完全不跟踪进度超时。这一语义从根上解决了分批发布暂停期间被误判超时的问题是本功能与 Deployment 最重要的区别。API 字段与配置完整 YAML 示例在 CloneSet 的spec下直接配置progressDeadlineSeconds默认值参照 Kubernetes 官方 Deployment 语义为 600 秒apiVersion: apps.kruise.io/v1alpha1 kind: CloneSet metadata: name: cloneset-example spec: replicas: 3 progressDeadlineSeconds: 600 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2字段定义位于 apis/apps/v1alpha1/cloneset_types.go// ProgressDeadlineSeconds specifies the maximum time for the CloneSet to reach available // or paused state due to partitioning. The controller will set a ProgressDeadlineExceeded // condition when timeout occurs, while excluding paused state duration from the deadline calculation. // This field is optional. If not set, the controller will not track progress deadlines or add the condition. ProgressDeadlineSeconds *int32 json:progressDeadlineSeconds,omitempty同时该字段也出现在生成的 CRD 中v1alpha1 与 v1beta1 两个版本均包含见 apps.kruise.io_clonesets.yaml。字段语义与校验规则结合字段注释与实现progressDeadlineSeconds的使用规则可以归纳为取值情况行为未设置nil控制器完全不跟踪进度超时不会写入Progressing条件已有条件会被移除设置为math.MaxInt322147483647等价于永不超时同样不跟踪进度 deadline见 cloneset_utils.go 的HasProgressDeadline设置为正常正整数值超时后写入ProgressDeadlineExceeded条件期间如进入 available / paused / partition-available 状态则重置计时在校验 Webhook 中创建或更新 CloneSet 时会对该字段做两项检查见 pkg/webhook/cloneset/validating/validation.go字段值必须为非负数ValidateNonnegativeField若值不等于math.MaxInt32则必须大于minReadySeconds否则报错must be greater than minReadySeconds。第二条约束有其合理性minReadySeconds定义了 Pod 需保持 ready 多久才算 available若 deadline 比它还小任何发布都必然超时属于无意义的配置。另外从 validation.go 可见v1alpha1 与 v1beta1 之间转换时该字段会被保留不会因版本转换而丢失。Condition 体系如何暴露进度状态超时与否、是否处于暂停全部通过 CloneSet 的.status.conditions中的Progressing条件对外暴露。相关的类型定义在 cloneset_types.gotype CloneSetConditionReason string const ( CloneSetProgressDeadlineExceeded CloneSetConditionReason ProgressDeadlineExceeded CloneSetProgressPaused CloneSetConditionReason CloneSetPaused CloneSetProgressUpdated CloneSetConditionReason CloneSetUpdated CloneSetProgressPartitionAvailable CloneSetConditionReason ProgressPartitionAvailable CloneSetAvailable CloneSetConditionReason CloneSetAvailable ) type CloneSetConditionType string const ( CloneSetConditionFailedScale CloneSetConditionType FailedScale CloneSetConditionFailedUpdate CloneSetConditionType FailedUpdate CloneSetConditionTypeProgressing CloneSetConditionType Progressing )CloneSetCondition结构体除Type、Status、Reason、Message外还包含LastUpdateTime与LastTransitionTime见 cloneset_types.go。其中LastUpdateTime承担了提案中保存 starttime计时起点的职责——超时判定正是基于该时间戳计算的。一个典型的超时后的status片段如下status: conditions: - lastTransitionTime: 2021-11-26T20:52:12Z lastUpdateTime: 2021-11-26T20:52:12Z message: CloneSet has minimum availability. reason: MinimumReplicasAvailable status: True type: Available - lastTransitionTime: 2024-03-10T12:00:00Z lastUpdateTime: 2024-03-10T12:00:00Z message: CloneSet revision 2 has timed out progressing reason: ProgressDeadlineExceeded status: False type: Progressing注意实际落地实现中超时消息为CloneSet revision rev has timed out progressing由 cloneset_status.go 生成与提案中的示例措辞略有差异以源码实现为准。控制器实现原理进度状态计算状态机提案中给出的伪代码思路是在控制器中加一个 timer 检查进度超时则追加ProgressingFalse / ProgressDeadlineExceeded条件到达 paused 或完成状态则重置计时。这一思路最终落地为realStatusUpdater.calculateProgressingStatus函数见 pkg/controller/cloneset/cloneset_status.go它在每次状态更新时被调用cloneset_status.go并按优先级依次命中以下分支未启用进度跟踪HasProgressDeadline为 false字段为 nil 或MaxInt32时直接移除已有Progressing条件并返回-1不要求 requeue。这对应用户删除了该字段/改用永不超时的场景测试用例见 cloneset_status_test.gopds is updated to nil与pds is updated to maxInt32两个用例。CloneSetAvailable发布完成当CurrentRevision UpdateRevision、Replicas、UpdatedReplicas、UpdatedAvailableReplicas均等于期望副本数时cloneset_utils.go写入ProgressingTrue / CloneSetAvailable条件并重置计时返回-1。CloneSetBePaused手动暂停当rollingUpdate.pausedtrue时cloneset_utils.go写入ProgressingTrue / CloneSetPaused暂停期间不计入 deadline——这正是提案第一种解释的直接体现。对应测试用例可见 cloneset_status_test.go即使此前已经ProgressDeadlineExceeded一旦进入 paused 状态条件会被重置为CloneSetPaused且不再要求 requeue。CloneSetPartitionAvailable分区暂停到位当用户配置了partition且ExpectedUpdatedReplicas replicas、ExpectedUpdatedReplicas UpdatedAvailableReplicas时cloneset_utils.go说明分批发布已推进到 partition 规定的数量写入ProgressingTrue / ProgressPartitionAvailable并重置计时。这实现了提案中当 CloneSet 到达 paused因 partition状态时重置 timer的要求。CloneSetDeadlineExceeded超时判定逻辑见 cloneset_utils.gofunc CloneSetDeadlineExceeded(cs *appsv1beta1.CloneSet, newStatus *appsv1beta1.CloneSetStatus, now time.Time) bool { condition : GetCloneSetCondition(*newStatus, appsv1beta1.CloneSetConditionTypeProgressing) if condition nil { return false } else if condition.Reason string(appsv1beta1.CloneSetProgressDeadlineExceeded) { return true } return condition.LastUpdateTime.Add(time.Duration(*cs.Spec.ProgressDeadlineSeconds) * time.Second).Before(now) }即以Progressing条件的LastUpdateTime为计时起点若LastUpdateTime progressDeadlineSeconds早于当前时间则判定超时写入ProgressingFalse / ProgressDeadlineExceeded条件消息为CloneSet revision rev has timed out progressing。一旦处于超时状态条件会持续保持直至状态机进入前面几种重置分支如发布完成、进入暂停、或pds被改为 nil/MaxInt32。默认分支正在推进写入ProgressingTrue / CloneSetUpdated消息为 CloneSet is progressing并返回一个 requeue 时长用于在 deadline 临近时精确唤醒控制器。与提案伪代码对应的核心判断——UpdatedReadyReplicas Replicas或replicas - updatedReplicas partition时重置 starttimepaused时重置 starttime——在实际实现中以上述 2、3、4 三个分支的形式落地且计时起点统一保存在条件的LastUpdateTime字段中保证了 controller 重启后仍能基于持久化状态继续计时而不是依赖内存中的starttime变量。超时判定与 requeue 机制在正在推进的默认分支中函数会调用getRequeueSecondsFromConditioncloneset_status.go计算距离 deadline 还剩多少秒func getRequeueSecondsFromCondition(condition *appsv1beta1.CloneSetCondition, progressDeadlineSeconds int32, now time.Time) time.Duration { if condition nil { return -1 } after : condition.LastUpdateTime.Time.Add(time.Duration(progressDeadlineSeconds) * time.Second).Sub(now) if after time.Second { return after } // this helps avoid milliseconds skew in AddAfter. return after time.Second }该返回值通过DurationStore见 cloneset_utils.go传递给调和循环最终作为reconcile.Result{RequeueAfter: ...}返回cloneset_controller.go从而在超时临界点精确唤醒控制器执行超时判定而不是依赖随机周期性的重新入队。这样既避免了对 API Server 的无效高频请求又能保证超时条件在 deadline 到达后第一时间被写入。此外hasProgressingConditionChangedcloneset_status.go会将Progressing条件的 Status/Reason 变化纳入状态不一致检测确保条件变化能被持久化到集群中。单元测试与 E2E 验证该功能在仓库中有充分的测试覆盖可作为理解与验证的参考单元测试pkg/controller/cloneset/cloneset_status_test.go 中的TestSyncProgressingStatus使用testingclock.NewFakeClock模拟时间覆盖了大量场景包括pds为 nil /MaxInt32/ 正常值、手动 paused、partition 暂停、ProgressDeadlineExceeded状态下修改pds、超时后进入暂停、超时后开始新 revision此时重新计时见 cloneset_status_test.go等工具函数测试pkg/controller/cloneset/utils/cloneset_utils_test.go 验证了HasProgressDeadline对 nil、600、MaxInt32三种取值的判断E2E 测试test/e2e/apps/v1alpha1/cloneset.go 中包含了以MaxInt32创建progressDeadlineSeconds、动态更新progressDeadlineSeconds、以及大量minReadySeconds与progressDeadlineSeconds组合如 10 与 600的滚动更新场景用于在真实集群中验证超时与不超时的行为。实战使用与排查指南开启进度超时检测在 CloneSetspec中添加progressDeadlineSeconds如 600。建议与minReadySeconds配合使用且 deadline 必须大于minReadySeconds否则会被 Webhook 拒绝。观察发布是否卡死发布期间持续查看.status.conditions若出现type: Progressing, status: False, reason: ProgressDeadlineExceeded说明发布在 deadline 内未取得可用进展需要排查镜像、探针、资源配额、partition配置等。区分真超时与假超时手动暂停rollingUpdate.pausedtrue或 partition 暂停期间的时间不计入 deadline条件会显示为CloneSetPaused/ProgressPartitionAvailable且status: True这属于正常状态不会被误判为超时。解除超时状态超时条件本身不会自愈。修复根因后发布推进到完成CloneSetAvailable或进入暂停状态时会自动重置计时并更新条件也可以通过将progressDeadlineSeconds改为更大的值、MaxInt32或直接删除该字段来停止跟踪。配合监控告警可以基于reasonProgressDeadlineExceeded的条件变化配置告警让发布静默卡死变成可被感知的告警事件。总结progressDeadlineSeconds为 OpenKruise CloneSet 补齐了与原生 Deployment 对齐的发布进度管控能力同时通过暂停与分区到达即重置计时的设计妥善处理了 CloneSet 特有的 partition 分批发布与手动暂停场景。从 提案文档 到 状态计算实现、判定工具函数、Webhook 校验 以及 E2E 用例整条链路清晰完整。读者可以结合上述源码路径深入阅读在实际集群中通过kubectl get cloneset -o yaml观察Progressing条件验证并掌握这一发布运维利器。赞分享云原生容器编排微服务运维【免费下载链接】kruiseAutomated management of large-scale applications on Kubernetes (incubating project under CNCF)项目地址https://gitcode.com/gh_mirrors/kr/kruise点击查看免费下载相关推荐KubeVela CloneSet 渐进式发布实战基于 AppRollout 的分批滚动升级与回滚指南KubeVela CloneSet 渐进式发布实战基于 AppRollout 的分批滚动升级与回滚指南 本指南完整演示如何在 KubeVela 中基于 Ope云原生DevOps运维微服务如何永久保存微信聊天记录WeChatMsg完整免费备份指南如何永久保存微信聊天记录WeChatMsg完整免费备份指南 在数字时代微信聊天记录承载着我们珍贵的记忆和重要的信息但官方不提供完整的导出功能数据安全令人上一篇Julia 边界检查Bounds Checking完全指南inbounds 与 boundscheck 的编译期消除机制与安全实践下一篇深入理解 JavaScript 基本包装类型String、Number、Boolean 的隐式转换机制创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考