ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Argo CD ApplicationSet 渐进式发布策略(Progressive Rollout Strategy)完整指南

2026/9/13 12:13:05 拓冰建站 浏览量
Argo CD ApplicationSet 渐进式发布策略(Progressive Rollout Strategy)完整指南 Argo CD ApplicationSet 渐进式发布策略Progressive Rollout Strategy完整指南【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cdArgo CD 的 ApplicationSet 控制器负责根据生成器Generator批量生成并维护 Application 资源。默认情况下当你修改 ApplicationSet 的 spec 或模板时所有被生成的 Application 会在同一时间被更新——这种全量同时生效的行为在面向多环境、多集群的场景下意味着配置错误的爆炸半径被瞬间放大。本文以 Argo CD 仓库中的设计提案 docs/proposals/2022-07-13-appset-progressive-rollout-strategy.md 为核心结合当前仓库中已落地的 Progressive Syncs 功能与源码实现系统讲解 ApplicationSet 渐进式发布策略的设计动机、策略语义、完整配置示例、运行机制与失败处理帮助你掌握如何让一次 ApplicationSet 变更按声明的顺序、受控地传播到所有目标环境。背景与动机为什么需要受控的 ApplicationSet 变更ApplicationSet 是 Argo CD 中面向 GitOps 批量管理的核心抽象。一个 ApplicationSet 常常同时面向多个环境dev / qa / prod、预定义的 staging 区域或其他目标配置。在没有发布策略的情况下ApplicationSet 控制器对 spec 或模板的任何修改都会立刻、同时地反映到所有生成的 Application 上。对于集群运维人员cluster operators而言这种一次性全量生效存在明显的风险一个配置错误会以远大于预期的爆炸半径blast radius扩散且没有任何窗口去验证变更的正确性。渐进式发布Progressive Rollout正是为了解决这一问题而提出让 ApplicationSet 的变更能够以声明式、可定义顺序的方式逐步推广使运维人员有机会在每一波更新中验证变更从而对发布过程建立信心。设计提案明确了两个核心目标与非目标目标用户对 ApplicationSet 的一次修改能够以受控的方式传播到其生成的全部 Application。启用该能力后Application 将按照声明式定义的顺序被更新而不是同时更新。非目标不处理由 Application 所引用的 Helm Chart 或原始 manifest 变更带来的受控发布。提案明确表示这类能力固然有价值但最初实现仅覆盖 ApplicationSet 自身的变更不涉及上游 source 内容的受控发布。两种使用场景从逐批推进到保持原状提案围绕两个典型使用场景展开设计。场景一声明式控制 Application 的更新顺序用户希望以声明方式控制 ApplicationSet 变更向其生成的 Application 资源的推广顺序。为此提案引入了RollingUpdate与RollingSync两种策略 spec其设计思路参考了 K8s 生态中其他控制器如 Deployment、Argo Rollouts、CAPI MachineDeployments 等。策略的核心语义如下滚动更新策略依据maxUpdate值确定性地选择要更新的 Application。若maxUpdate为 1则 Application 逐个更新只有前一个 Application 的同步成功完成后才推进到下一个若大于 1则并行更新的数量不超过该值。滚动更新的步骤由一组matchExpressions标签选择器列表定义。每个步骤必须完成更新后下一步才能推进。若未定义步骤则 Application 的更新顺序是确定性的按内部排序推进。场景二保留原有的全量同时更新行为仍有一部分用户希望继续使用 ApplicationSet 控制器原有的同时更新行为。提案规定如果未提供任何 strategy则默认采用AllAtOnce策略该策略完整保留当前控制器的默认行为。策略配置完整示例提案给出了一个完整的 ApplicationSet spec 示例其中strategy字段定义了滚动更新步骤。以下为提案原始示例已保留原文语义apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: guestbook spec: generators: - list: elements: - cluster: engineering-dev url: https://1.2.3.4 env: dev - cluster: engineering-prod url: https://2.4.6.8 env: prod - cluster: engineering-qa url: https://9.8.7.6/ env: qa strategy: type: RollingUpdate rollingUpdate: steps: - matchExpressions: - key: env operator: In values: - dev maxUpdate: 0 # if undefined or 0, all applications matched are updated together - matchExpressions: - key: env operator: In values: - qa - matchExpressions: - key: env operator: In values: - us-east-2 - eu-west-1 - ap-southeast-1 maxUpdate: 1 # maxUpdate supports both integer and percentage string values template: metadata: name: {{cluster}}-guestbook labels: env: {{env}} # label can be provided explicitly from a list generator region: {{metadata.labels.cluster/region}} # or pulled from labels on the argo cluster secrets spec: source: repoURL: https://github.com/infra-team/cluster-deployments.git targetRevision: HEAD path: guestbook/{{cluster}} destination: server: {{url}} namespace: guestbook该示例的运行逻辑为当 guestbook ApplicationSet 被创建或修改时Application 资源按照strategy.rollingUpdate中定义的顺序依次更新第一步所有标签匹配表达式env: dev的 Application无论是否已 apply被更新为匹配模板。由于该步骤maxUpdate为 0所有匹配的 Application 并行更新。第二步所有标签为env: qa的 Application 同时更新因为该步骤未定义maxUpdate视为无上限。第三步标签为region: us-east-2、eu-west-1或ap-southeast-1的 Application 逐个更新因为该步骤的maxUpdate为 1。关键约束无论maxUpdate取值多少只有当前步骤内的所有 Application 全部成功推进并恢复健康后才进入下一步骤。maxUpdate仅限制当前步骤中同时处于更新状态的 Application 总数上限。提案同时定义了一次 Application 滚动发布完成rollout complete的判定标准——当 Application 资源满足以下全部条件时视为完成已成功同步Synced successfully。已进入Progressing状态。已离开Progressing状态并进入Healthy状态。RollingSync 与渐进式同步Progressive Syncs提案指出RollingSync使用与RollingUpdate相同的 spec但它是 Skyscanner/applicationset-progressive-sync 工具的重新实现。它侦测到 Application 变为 OutOfSync并按照 Application 策略 spec 中声明的顺序对这些 Application 触发同步操作。在 Argo CD 当前的正式文档 docs/operator-manual/applicationset/Progressive-Syncs.md 中该能力被命名为Progressive Syncs自 v3.3.0 起作为 Beta 功能提供用于控制 ApplicationSet 控制器创建或更新其管理的 Application 的顺序。当前仓库最终实现采纳的是RollingSync而非提案中的RollingUpdate并额外提供了删除顺序deletionOrder控制。启用方式作为实验性功能Progressive Syncs 必须显式启用可通过以下任意一种方式给 ApplicationSet 控制器进程传入--enable-progressive-syncs参数在 ApplicationSet 控制器的环境变量中设置ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCStrue在 Argo CD 的argocd-cmd-params-cmConfigMap 中设置applicationsetcontroller.enable.progressive.syncs: true。在源码层面控制器通过EnableProgressiveSyncs字段接收该开关见 applicationset/controllers/applicationset_controller.go 中的 reconcile 逻辑只有启用后才会进入渐进式同步的处理分支未启用时控制器会清理任何残留的 ApplicationSet 状态避免脏数据。创建策略Creation Strategiesstrategy.type字段控制 Application 的创建与更新方式可用值AllAtOnce默认保持原始 ApplicationSet 实现不变ApplicationSet 更新时所有被管理的 Application 同时更新。spec: strategy: type: AllAtOnce # explicit, but this is the defaultRollingSync允许按生成的 Application 资源上的标签对 Application 分组。ApplicationSet 变更时变更按组顺序依次应用到各组。其语义要点Application 分组使用其标签与matchExpressions选择多个表达式之间为AND关系——一个 Application 必须满足全部表达式才会被选中In/NotIn运算符的多个值之间为OR关系——匹配到任意一个值即视为满足当NotIn与In同时产生匹配时NotIn具有优先级每组内的所有 Application 必须全部变为 Healthy 后控制器才推进到下一组组内同时更新的 Application 数量不会超过其maxUpdate参数默认 100%即无上限RollingSync 依赖侦测被管理 Application 的 OutOfSync 状态因此能够捕获 ApplicationSet 资源之外的变更RollingSync 会强制所有生成的 Application 禁用自动同步autosync若用户的 Application spec 中启用了自动同步策略控制器日志会打印警告同步操作与 UI 或 CLI 触发的同步方式相同直接设置 Application 资源的operation字段因此会遵守同步窗口sync windows触发同步时使用 Application 自身配置的 syncPolicy例如保留其重试retry设置未被任何步骤选中的 Application 会被排除在滚动同步之外需要手动通过 CLI 或 UI 同步。一个典型的两步 RollingSync 配置示例spec: strategy: type: RollingSync rollingSync: steps: - matchExpressions: - key: envLabel operator: In values: - env-dev - matchExpressions: - key: envLabel operator: In values: - env-prod maxUpdate: 10%其执行过程为标签为envLabelenv-dev的 Application 首先被选中同步。由于未定义maxUpdate默认按 100% 处理所有匹配的 Application 同时同步控制器等待每个被选中的 Application 达到 Healthy 状态后才进入下一步。随后标签为envLabelenv-prod的 Application 被选中同步每次仅同步匹配应用中的 10%每批 Application 达到 Healthy 后同步下一批直至全部完成。不匹配任何表达式的 Application 不会由 RollingSync 同步必须手动处理。删除策略Deletion Strategiesstrategy.deletionOrder字段控制 Application 被从 ApplicationSet 移除时的删除顺序可用值AllAtOnce默认所有待删除的 Application 同时删除。该行为同时适用于AllAtOnce与RollingSync创建策略。spec: strategy: type: RollingSync # or AllAtOnce deletionOrder: AllAtOnce # explicit, but this is the defaultReverse与RollingSync策略搭配使用时Application 按rollingSync.steps定义步骤的逆序删除——即后部署的处于靠后步骤的Application 先删除先部署的处于靠前步骤的Application 后删除。这适合需要按特定顺序拆除依赖服务的场景例如先删前端服务再删其依赖的后端服务。Reverse 删除的要求与注意事项必须与type: RollingSync搭配使用必须定义rollingSync.stepsApplication 按步骤序列的逆序删除ApplicationSet 的 finalizer 在所有 Application 成功删除前不会移除从而保证清理的完整性防止 ApplicationSet 在其管理的 Application 之前被删除当deletionOrder为Reverse且启用渐进式同步时控制器会确保 ApplicationSet 存在 finalizer若缺失控制器会在生成 Application 之前为 ApplicationSet 补上 finalizer。Reverse 删除示例spec: strategy: type: RollingSync deletionOrder: Reverse rollingSync: steps: - matchExpressions: - key: envLabel operator: In values: - env-dev # Step 1: Created first, deleted last - matchExpressions: - key: envLabel operator: In values: - env-prod # Step 2: Created second, deleted first删除时env-prod步骤 2的 Application 先被删除env-dev步骤 1的 Application 后被删除。综合示例带 Reverse 删除的滚动发布以下来自正式文档的示例演示了如何对带有显式环境标签的 Application 进行分阶段渐进同步apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: guestbook spec: generators: - list: elements: - cluster: engineering-dev url: https://1.2.3.4 env: env-dev - cluster: engineering-qa url: https://2.4.6.8 env: env-qa - cluster: engineering-prod url: https://9.8.7.6/ env: env-prod strategy: type: RollingSync deletionOrder: Reverse # Applications will be deleted in reverse order of steps rollingSync: steps: - matchExpressions: - key: envLabel operator: In values: - env-dev #maxUpdate: 100% # if undefined, all applications matched are updated together (default is 100%) - matchExpressions: - key: envLabel operator: In values: - env-qa maxUpdate: 0 # if 0, no matched applications will be updated - matchExpressions: - key: envLabel operator: In values: - env-prod maxUpdate: 10% # maxUpdate supports both integer and percentage string values (rounds down, but floored at 1 Application for 0%) goTemplate: true goTemplateOptions: [missingkeyerror] template: metadata: name: {{.cluster}}-guestbook labels: envLabel: {{.env}} spec: project: my-project source: repoURL: https://github.com/infra-team/cluster-deployments.git targetRevision: HEAD path: guestbook/{{.cluster}} destination: server: {{.url}} namespace: guestbook推送一次变更后控制器按如下顺序执行所有env-devApplication 同时更新等待所有env-qaApplication 通过argocdCLI 或 UI 的 Sync 按钮手动同步因为该步骤maxUpdate: 0表示不自动更新任何匹配的 Application所有env-prodApplication 按 10% 一批的方式逐批更新直至全部完成。源码视角策略在 ApplicationSet CRD 中的落地从当前仓库的 CRD 类型定义pkg/apis/application/v1alpha1/applicationset_types.go可以看到ApplicationSetSpec中新增了Strategy *ApplicationSetStrategy字段其类型结构为// ApplicationSetStrategy configures how generated Applications are updated in sequence. type ApplicationSetStrategy struct { Type string json:type,omitempty protobuf:bytes,1,opt,nametype RollingSync *ApplicationSetRolloutStrategy json:rollingSync,omitempty protobuf:bytes,2,opt,namerollingSync // DeletionOrder allows specifying the order for deleting generated apps when progressive sync is enabled. // accepts values AllAtOnce and Reverse DeletionOrder string json:deletionOrder,omitempty protobuf:bytes,3,opt,namedeletionOrder } type ApplicationSetRolloutStrategy struct { Steps []ApplicationSetRolloutStep json:steps,omitempty protobuf:bytes,1,opt,namesteps } type ApplicationSetRolloutStep struct { MatchExpressions []ApplicationMatchExpression json:matchExpressions,omitempty protobuf:bytes,1,opt,namematchExpressions MaxUpdate *intstr.IntOrString json:maxUpdate,omitempty protobuf:bytes,2,opt,namemaxUpdate } type ApplicationMatchExpression struct { Key string json:key,omitempty protobuf:bytes,1,opt,namekey Operator string json:operator,omitempty protobuf:bytes,2,opt,nameoperator Values []string json:values,omitempty protobuf:bytes,3,opt,namevalues }从结构可以看出几个关键设计决策MaxUpdate使用*intstr.IntOrString类型这正是同时支持整数与百分比字符串的原因。源码在计算时通过intstr.GetScaledValueFromIntOrPercent将百分比换算为具体数量并且当百分比大于 0% 时换算结果至少为 1 个 Application即0%的百分比向下取整、但保底 1 个见 applicationset/progressivesync/progressive_sync.go 中UpdateApplicationSetApplicationStatusProgress的实现。ApplicationMatchExpression复用了 Kubernetes 标签选择器的表达模型Key/Operator/Values源码中标签匹配labelMatchedExpression仅支持In与NotIn两种运算符并实现了NotIn优先的语义。DeletionOrder作为策略的独立字段出现与创建策略解耦但其Reverse语义依赖RollingSync策略与步骤定义。源码视角渐进式同步的执行管线渐进式同步的核心执行逻辑位于 applicationset/progressivesync/progressive_sync.go 中的Manager并在 applicationset/controllers/applicationset_controller.go 的 reconcile 流程中被调用。整个执行管线大致如下构建步骤与应用的映射关系buildAppDependencyList读取strategy.rollingSync.steps遍历当前 Application 的标签按每个 step 的matchExpressions把 Application 分派到对应步骤得到appDependencyList每步的应用名列表与appStepMap应用名到步骤的映射。若某 Application 未被任何表达式选中则其步骤默认为-1不参与滚动。该函数同时收集校验问题无效的表达式运算符、同一个 Application 被多个步骤重复选中、空步骤等。状态机推进UpdateApplicationSetApplicationStatus依据每个 Application 的 Sync/Health 状态与目标 revision 变化在Waiting → Pending → Progressing → Healthy之间推进状态状态常量定义于 pkg/apis/application/v1alpha1/applicationset_types.go分别为ProgressiveSyncWaiting、ProgressiveSyncPending、ProgressiveSyncProgressing、ProgressiveSyncHealthy并将结果持久化到 ApplicationSet 的status.applicationStatus。计算本波可同步的 ApplicationgetAppsToSync逐步骤判断——只有某步骤内的全部 Application 都处于 Healthy 状态时才继续允许下一波更新否则停止推进。maxUpdate 限流UpdateApplicationSetApplicationStatusProgress统计当前步骤中处于Pending/Progressing的 Application 数量与maxUpdate换算值比较超过则不允许该 Application 从Waiting转为Pending从而实现最多同时更新 N 个。触发同步SyncDesiredApplications仅对处于Pending状态的 Application 触发同步——通过直接设置 Application 的operation字段操作发起人为applicationset-controller并带有ApplicationSet RollingSync triggered a sync的原因标注。同步会继承 Application 自身的重试策略默认与 appcontroller 自动同步一致的重试上限 5并保留其 syncOptions 与 prune 设置。由于 RollingSync 强制关闭自动同步disableAutomatedSync同步完全由控制器按策略节奏触发不会被用户配置的 automated syncPolicy 抢跑。revision 固定当某步骤被解锁时会记录该步骤对应的TargetRevisions并在触发同步时将其固定pin到 sync 操作中——这样即使在滚动过程中有新 commit 落地也不会劫持正在进行的步骤使其同步到未经校验的更新 revision。在执行过程中控制器还会向 ApplicationSet 的状态写入两类条件RolloutProgressing当存在未完成的步骤时为True消息形如ApplicationSet is performing rollout of step N全部完成后为False消息为ApplicationSet Rollout has completed。InvalidRolloutConfig当策略配置存在问题时无效运算符、重复选中、空步骤、非法maxUpdate消息会具体说明问题所在例如Step 2 has invalid matchExpression operators: ... Supported Operators are In and NotIn或Application foo is selected by multiple steps详见 applicationset/progressivesync/validation_issues.go。此外控制器在RefreshGracePeriodSeconds窗口内会等待所有 Application 完成一次 reconcile必要时通过argocd.argoproj.io/refresh注解强制刷新后才继续推进滚动避免在状态尚未稳定时过早判断。初始创建与变更期间的发布行为提案对初始创建与滚动失败两类特殊场景给出了明确设计初始 ApplicationSet 创建带有已定义策略的全新 ApplicationSet 首次创建时Application 资源的创建过程与更新过程类似——每个 Application 按步骤定义的顺序创建仅当某一步成功完成后才推进到下一步。同理当 ApplicationSet 被修改为指向不同的目标集群或命名空间集合时Application 的创建或更新也按照其期望状态与策略中定义的步骤顺序进行。滚动失败Rollout Failure若 ApplicationSet 的 spec 或模板被修改后某个目标 Application 在任何步骤中未能完成同步则 ApplicationSet 的滚动发布被阻塞stalled。ApplicationSet 会确保status中的ApplicationSetUpToDate条件为False。此时若maxUpdate允许ApplicationSet 会继续更新当前步骤内的其他 Application否则不再向 Application 资源传播任何进一步变更且任何步骤都不会推进直到每个 Application 都能成功完成一次同步。如果 ApplicationSet 在滚动发布过程中无论是否阻塞再次被修改则放弃当前滚动Application 资源保持其当前状态随即开始新一轮滚动。在正式文档的示例中maxUpdate: 0还被用作暂停该步骤的自动更新的手段——该步骤匹配的 Application 不会被自动同步而是等待人工通过 CLI 或 UI 手动触发从而为发布流程引入人工审批窗口。关于暂停实现的取舍提案讨论了实现尚未就绪的 Application 暂停更新的几种方案禁用自动同步Disable auto-sync可能与应用自身配置的自动同步设置冲突优点是能够看到 ApplicationSet 变更的完整 diff。暂停Application当时尚未实现对应 issue #4808。通过滚动更新策略阻止对存量 Application 的任何更新这被确定为初始实现的首选方案——从当前仓库源码看这一方案正是最终落地的形态RollingSync策略强制生成的所有 Application 关闭自动同步同步完全由控制器按步骤与maxUpdate节奏触发。安全与风险考量安全考量提案认为该特性不会给 ApplicationSet 控制器带来新的安全考量。风险与缓解提案指出后续自然的演进方向是解决Application 的 source 上游变更的受控发布问题——典型场景是对未版本化的 wrapper Helm Chart依赖版本化上游 Chart常用于补充公司级 RBAC 或 ExternalSecrets 等辅助资源的模板或 values 修改希望也能按顺序推广。实现该能力存在一定难度因为 ApplicationSet 控制器需要拦截 Application 的同步操作以防止变更自动同步。此外新增特性总是会给 Argo CD 团队带来额外的维护负担——这也是所有新功能的固有风险。升级与降级策略升级新特性仅向 ApplicationSet CRD 引入新字段strategy未改动任何现有字段因此无需引入新的 ApplicationSet API 版本升级到带新增字段的新 spec 是干净的clean操作。降级若用户降级 CRD 后仍继续向 ApplicationSet 资源应用strategy字段会收到 K8s API 错误。而仅降级控制器、保留升级版 CRD则不会破坏现有 ApplicationSet spec控制器行为可干净地回退到旧版本。备选方案对比提案还记录了在设计中考虑过的两种替代方案以及最终放弃它们的原因创建独立的 CRD 来管理 ApplicationSet 的滚动发布过程最终放弃因为调研发现 K8s 生态中其他滚动策略K8s Deployment、Argo Rollouts、CAPI MachineDeployments 等均将策略实现在同一 CRD 资源内。通过 application-controller 实现 Application Dependencies应用依赖 DAG这一方案要复杂得多需要实现并维护一个 Application 依赖有向无环图DAG。小结ApplicationSet 渐进式发布策略将 ApplicationSet 从全量同时生效升级为声明式、分步骤、可限流、可失败恢复的受控发布模型。当前仓库以RollingSyncProgressive Syncs形式落地了该提案通过strategy.type控制创建/更新顺序通过strategy.deletionOrder控制删除顺序通过steps[].matchExpressions按标签分组、steps[].maxUpdate限制并发、ApplicationSetUpToDate/RolloutProgressing/InvalidRolloutConfig等状态条件反馈发布进度与配置问题。对于需要跨多环境、多集群谨慎发布变更的 GitOps 团队而言这提供了一条低风险、可验证的发布路径。进一步阅读功能完整文档见 docs/operator-manual/applicationset/Progressive-Syncs.md类型定义见 pkg/apis/application/v1alpha1/applicationset_types.go核心执行逻辑见 applicationset/progressivesync/progressive_sync.go控制器集成见 applicationset/controllers/applicationset_controller.go设计提案原文见 docs/proposals/2022-07-13-appset-progressive-rollout-strategy.md。【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考