Argo CD ApplicationSet Progressive Syncs 实战指南:基于 RollingSync 的渐进式应用发布与回滚删除
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
导读
Progressive Syncs(渐进式同步)是 Argo CD ApplicationSet 提供的Beta 功能(自 v3.3.0 起),它允许你控制 ApplicationSet 控制器创建、更新乃至删除其托管 Application 的顺序。通过为生成的 Application 打上标签并按matchExpressions分组,你可以实现"先灰度环境、再验证环境、最后生产环境分批发布"的滚动式发布流程,并让每一步都等待前一批应用进入Healthy状态后再继续。读完本文,你将掌握 Progressive Syncs 的启用方式、RollingSync创建策略与Reverse删除策略的完整配置,并能结合源码理解其底层状态机(Waiting → Pending → Progressing → Healthy)与最终器(finalizer)保障机制。
功能状态:Beta。该功能整体稳定,但可能仍存在未覆盖的边缘场景。相关实现位于 applicationset/progressivesync/progressive_sync.go。
使用场景与设计边界
Progressive Syncs 的设计目标被刻意保持为轻量且灵活:
- 该功能只与托管 Application 的健康状态(Health)交互,不会与 Argo Rollouts、原生 ReplicaSet 控制器等"回滚控制器"直接集成。
- 控制器会监听托管 Application 变为
Healthy才进入下一阶段。 - 由于应用在 Pod 滚动期间会进入
Progressing状态,因此 Deployment、DaemonSet、StatefulSet 以及 Argo Rollouts 都天然受支持;实际上,任何健康检查能够报告Progressing状态的资源都受支持(见 gitops-engine/pkg/health 的健康状态定义)。 - Argo CD Resource Hooks(资源钩子)同样受支持,例如 sync-waves(同步波次)。官方建议:在无法使用 Argo Rollout 但又需要高级功能的场景(例如 DaemonSet 变更后的冒烟测试)下,优先采用这一方案。
启用 Progressive Syncs
作为实验性功能,Progressive Syncs 必须显式开启,三种方式任选其一:
- 命令行参数:在 ApplicationSet 控制器启动参数中传入
--enable-progressive-syncs; - 环境变量:设置
ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=true; - ConfigMap:在 Argo CD 的
argocd-cmd-params-cmConfigMap 中设置applicationsetcontroller.enable.progressive.syncs: "true"。
从源码看,命令行标志通过环境变量兜底解析,默认均为false,见 cmd/argocd-applicationset-controller/commands/applicationset_controller.go:
command.Flags().BoolVar(&enableProgressiveSyncs, "enable-progressive-syncs", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS", false), "Enable use of the experimental progressive syncs feature.")启用后,控制器在协调循环(reconcile)中才会进入渐进式同步分支。注意两点行为差异(见 applicationset/controllers/applicationset_controller.go):
- 若功能开启,但某个 ApplicationSet 的策略从
RollingSync切回了默认策略,控制器会清理残留的ApplicationStatus条目; - 若功能关闭,控制器同样会清空所有
ApplicationStatus,避免脏数据残留。
策略总览:创建与删除是两个独立字段
ApplicationSet 的策略(spec.strategy)同时控制应用的创建/更新与删除,二者由两个独立字段配置:
| 字段 | 控制对象 | 可选值 |
|---|---|---|
type | 应用的创建与更新顺序 | AllAtOnce(默认)、RollingSync |
deletionOrder | 应用的删除顺序 | AllAtOnce(默认)、Reverse |
创建策略(Creation Strategies)
AllAtOnce(默认)
这是 ApplicationSet 的原始默认行为:ApplicationSet 一旦更新,其管理的所有 Application 将同时被更新,行为与未启用 Progressive Syncs 时完全一致。
spec: strategy: type: AllAtOnce # 显式声明,但该值本就是默认值RollingSync
该更新策略允许你按生成 Application 资源上的标签进行分组:当 ApplicationSet 变化时,变更将按组依次应用到各 Application。
其核心语义如下:
- 分组通过 Application 的
labels与matchExpressions完成选择; - 一个 Application 必须满足某步内的所有
matchExpressions才会被选中(多个表达式之间是AND关系); In与NotIn操作符:只要匹配到至少一个values值即为真(OR关系);- 当
NotIn与In同时命中时,NotIn优先级更高; - 每个分组内的所有 Application必须全部变为
Healthy,控制器才会继续更新下一组; - 同组内并发更新的 Application 数量不超过
maxUpdate参数(默认 100%,即不设上限); - RollingSync会捕获 ApplicationSet 资源之外的变更,因为它依赖监听托管 Application 的
OutOfSync状态; - RollingSync会强制所有生成的 Application 关闭自动同步(autosync),凡是在 Application 规范里配置了自动同步策略的,都会在 applicationset-controller 日志中打印警告;
- Sync 操作的触发方式与在 UI/CLI 中手动触发完全一致(即直接设置 Application 资源的
operation状态字段),因此RollingSync 会像用户在 Argo UI 点击"Sync"按钮一样遵守同步窗口(sync windows); - 触发同步时,沿用 Application 自身配置的 syncPolicy,例如保留其重试(retry)设置;
- 未被任何步骤选中的 Application 会被排除在滚动同步之外,需要手动通过 CLI 或 UI 同步。
配置示例——两个发布步骤:
spec: strategy: type: RollingSync rollingSync: steps: - matchExpressions: - key: envLabel operator: In values: - env-dev - matchExpressions: - key: envLabel operator: In values: - env-prod maxUpdate: 10%该示例的执行过程:
- 第一步:所有带标签
envLabel=env-dev的 Application 被选中先同步。由于未定义maxUpdate,采用默认值 100%,所有匹配的 Application 将同时同步;控制器等待每个被选中的应用都达到Healthy状态,才进入下一步; - 第二步:所有带标签
envLabel=env-prod的 Application 被选中同步,但这里maxUpdate: 10%意味着每次只同步匹配应用中的 10%。每一批应用达到Healthy后,再同步下一批,直到全部匹配应用完成同步。
若存在未匹配任何表达式的应用,它们不会被 RollingSync 策略同步,必须如前文所述手动同步。
maxUpdate 的取值规则(源码佐证)
在 applicationset/progressivesync/progressive_sync.go 的UpdateApplicationSetApplicationStatusProgress中:
maxUpdate同时支持整数与百分比字符串两种写法(底层为intstr.IntOrString,经GetScaledValueFromIntOrPercent换算);- 百分比值向下取整,但对于大于 0% 的值,至少保证有 1 个 Application 被选中(
maxUpdateVal < 1时强制置为 1); maxUpdate: 0表示该步骤不会更新任何匹配的 Application;- 若
maxUpdate值非法,控制器会记录一条InvalidMaxUpdates校验问题,并忽略该步骤的 maxUpdate 逻辑(即退化为不限数量)。
分组选择逻辑(源码佐证)
buildAppDependencyList(见 progressive_sync.go)负责把当前 Application 按步骤分桶:
- 对每个步骤的每个
matchExpression,先查 Application 是否含对应 label key:In操作符下缺 key 即不入选;NotIn下缺 key 则视为匹配; - 一个 Application 被多个步骤选中时,会打印警告并记录为
DuplicateAppSelections校验问题; - 没有任何 Application 匹配的步骤会被记录为
EmptySteps(空步骤); - 未被任何表达式选中的 Application 在步骤映射中默认落在step -1(见
getAppStep),即被排除在滚动同步之外。
校验与状态条件(源码佐证)
ValidationIssues(见 applicationset/progressivesync/validation_issues.go)会收集四类问题:非法matchExpression操作符(仅支持In/NotIn)、重复选中、空步骤、非法maxUpdate。当存在问题时,控制器会在 ApplicationSet 上设置ApplicationSetConditionInvalidRolloutConfig条件,并优先报告其中优先级最高的一项。
同时,控制器会根据各步骤是否全部Healthy来维护ApplicationSetConditionRolloutProgressing条件(getProgressingCondition,见 progressive_sync.go):进行中时消息为ApplicationSet is performing rollout of step N,完成时为ApplicationSet Rollout has completed。
底层状态机:Waiting → Pending → Progressing → Healthy
从UpdateApplicationSetApplicationStatus与UpdateApplicationSetApplicationStatusProgress的实现(progressive_sync.go)可以看到,每个 Application 在渐进式同步中经历以下状态:
- Waiting(等待):检测到目标修订(TargetRevisions)或期望 spec 与当前不一致(非 Git 变更,例如生成器参数变化)时进入;控制器会比较 revision 与 spec(通过
SpecsEquivalent与BuildIgnoreDiffConfig,支持ignoreApplicationDifferences配置); - Pending(待定):当前步骤满足"所有前序步骤均 Healthy"且未超过
maxUpdate配额后,由UpdateApplicationSetApplicationStatusProgress推进; - Progressing(进行中):观测到 Application 触发了同步操作(
OperationState)后进入;若 Application 存在错误条件(如InvalidSpecError、UnknownError),也会直接推进到 Progressing 以暴露问题; - Healthy(健康):Application 的 Health 为
Healthy且 Sync 状态为Synced时达成,此时才算该波次完成。
此外,PerformProgressiveSyncs在开始前会通过ensureApplicationsReconciled(progressive_sync.go)确保所有 Application 已在最近一次变更之后完成协调(reconcile),必要时会给应用添加 refresh annotation 强制刷新;refresh-grace-period-seconds(默认 30 秒,环境变量ARGOCD_APPLICATIONSET_CONTROLLER_REFRESH_GRACE_PERIOD_SECONDS)用于控制强制刷新前的宽限期。
同步触发方式(源码佐证)
SyncDesiredApplications与syncApplication(progressive_sync.go)展示了滚动同步如何触发同步:
- 只为处于Pending状态的 Application 触发同步,并锁定到该步骤解除阻塞时记录的 TargetRevisions,避免发布中途新提交"劫持"已在进行中的步骤;
- 通过构造
Operation(InitiatedBy为applicationset-controller、Automated: true)写入 Application 的operation字段,与 UI/CLI 手动触发路径一致; - 默认设置重试上限
Retry.Limit = 5,与 Argo CD 应用控制器的自动同步行为保持一致;若 Application 的 syncPolicy 配置了自定义retry,则以其为准; - 同步时携带 Application 的
syncOptions与prune设置; - 同时强制关闭生成应用的自动同步(
disableAutomatedSync),这正是文档所述"RollingSync 会强制所有生成的 Application 关闭 autosync"的底层实现。
删除策略(Deletion Strategies)
deletionOrder字段控制应用从 ApplicationSet 移除时的删除顺序。
AllAtOnce 删除(默认)
所有需要删除的 Application同时被删除。该模式与AllAtOnce和RollingSync两种创建策略均可搭配使用。
spec: strategy: type: RollingSync # 或 AllAtOnce deletionOrder: AllAtOnce # 显式声明,但该值本就是默认值Reverse 删除(逆序删除)
当RollingSync策略搭配deletionOrder: Reverse时,应用将按rollingSync.steps中定义步骤的逆序被删除:越晚部署的应用越先删除。这在需要按特定顺序拆除依赖服务时尤其有用——例如先删前端服务,再删后端依赖。
Reverse 删除的硬性要求:
- 必须与
type: RollingSync搭配使用; - 必须定义
rollingSync.steps; - 应用严格按照步骤序列的逆序删除。
重要保障机制:
- ApplicationSet 的 finalizer 在所有 Application 成功删除前不会被移除,这确保了清理的完整性,防止 ApplicationSet 在托管应用之前被删除;
- 当
deletionOrder设置为Reverse且渐进式同步启用时,ApplicationSet 控制器会确保存在 finalizer:如果 ApplicationSet 缺少必需的 finalizer,控制器会在生成应用之前自动为它添加(见 applicationset/controllers/applicationset_controller.go)。
spec: strategy: type: RollingSync deletionOrder: Reverse rollingSync: steps: - matchExpressions: - key: envLabel operator: In values: - env-dev # 步骤 1:最先创建,最后删除 - matchExpressions: - key: envLabel operator: In values: - env-prod # 步骤 2:第二个创建,最先删除删除时执行顺序:
env-prod的应用(步骤 2)先删除;env-dev的应用(步骤 1)后删除。
该顺序适合"拆除依赖服务"的场景,例如先删除前端服务、再删除其后端依赖。
Reverse 删除的底层实现(源码佐证)
PerformReverseDeletion(见 progressive_sync.go)实现了逆序删除:
- 先通过
buildAppDependencyList得到每个应用所属步骤,再按stepLength - appStep - 1计算逆序优先级并排序,逐级触发Client.Delete; - 每个步骤删除后控制器会以 10 秒为间隔重新入队(requeue),持续轮询直到对象消失;
- 对"已经标记删除但迟迟未消失"的应用,若超过2 分钟(
staleCacheThreshold)仍未消失,控制器会绕过 informer 缓存直接向 API Server 求证(通过APIReader),区分"删除缓慢"与"DELETED 事件丢失导致的幽灵缓存项"两种情形,必要时通过带 UID 前置条件的 Delete 触发缓存驱逐,避免幽灵条目阻塞 finalizer 的释放(相关回归测试见 applicationset/progressivesync/phantom_livecheck_test.go); - 整个流程结束(全部删除完成)后才返回,控制器才会释放 ApplicationSet 的 finalizer。
完整示例:分环境渐进式发布 guestbook
下面的完整示例演示了如何为显式配置了环境标签的 Application 编排一次渐进式发布。当一次变更被推送后,将按顺序发生如下动作:
- 所有
env-dev的 Application同时更新; - 滚动过程会等待所有
env-qa的 Application 通过argocdCLI 或 UI 中的 Sync 按钮被手动同步; - 所有
env-prod的 Application 将每次更新 10%,直到全部更新完毕。
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 # 应用将按步骤逆序删除 rollingSync: steps: - matchExpressions: - key: envLabel operator: In values: - env-dev #maxUpdate: 100% # 若不定义,默认一次更新所有匹配应用(默认 100%) - matchExpressions: - key: envLabel operator: In values: - env-qa maxUpdate: 0 # 若为 0,则不会更新任何匹配的应用 - matchExpressions: - key: envLabel operator: In values: - env-prod maxUpdate: 10% # maxUpdate 支持整数和百分比字符串(向下取整,但 >0% 时至少为 1 个应用) goTemplate: true goTemplateOptions: ['missingkey=error'] 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要点解读:
goTemplate: true开启 Go 模板渲染生成器参数,envLabel标签来自生成器的env字段,是步骤选择(matchExpressions)的匹配依据;maxUpdate: 0让env-qa步骤"只等待、不自动同步",配合手动同步使用;deletionOrder: Reverse保证删除时按env-prod → env-qa → env-dev的顺序逆序进行;- 模板中的
project、source、destination是 Application 的标准字段,会被渐进式同步流程原样继承。
参考实现与延伸阅读
- 渐进式同步核心实现:applicationset/progressivesync/progressive_sync.go
- 配置校验问题模型:applicationset/progressivesync/validation_issues.go
- 渐进式同步单元测试:applicationset/progressivesync/progressive_sync_test.go、applicationset/progressivesync/specchanged_regression_test.go
- ApplicationSet 控制器集成逻辑:applicationset/controllers/applicationset_controller.go
- 控制器启动参数与环境变量:cmd/argocd-applicationset-controller/commands/applicationset_controller.go
- 配合使用的同步波次(Resource Hooks):docs/user-guide/sync-waves.md
注意事项与限制
- Beta 功能:开启后请先在非生产环境验证,关注控制器日志中的警告(例如自动同步被强制关闭、非法
maxUpdate、重复选中、空步骤等提示); - 不要混用自动同步:RollingSync 会强制关闭托管应用的自动同步并打印警告,请确保模板中未配置
syncPolicy.automated,避免行为冲突; - 未命中步骤的应用需手动同步:任何未被
matchExpressions选中的应用都不会被自动更新; - 删除依赖最终器:Reverse 删除依赖 ApplicationSet finalizer 保障顺序,请勿手动移除该 finalizer,否则可能破坏删除顺序保障。
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考