LabHub
学习 学习路径 课程

GitOps 与 Argo CD

Application — 把部署本身变成一个对象

在 LabHub 中继续学习

一句话总结

ArgoCD 的 Application 不是部署脚本,而是一项声明:“这个仓库的这条路径应当成为那个集群中那个命名空间的状态。” 这项声明本身也是集群内的对象。

概念图: “这个仓库的这条路径应当成为那个集群中那个命名空间的状态。” · prune · selfHeal · 以固定间隔无限重试,会变成持续冲击 API 服务器的负载发生器。

为什么需要了解这些

如果用 CI 脚本编写发布流水线,部署配置就会被封闭在流水线定义中。要知道哪个应用部署到哪个命名空间、谁有权部署该应用,就必须阅读位于集群外部的脚本。因此,无法直接询问集群“这里部署了哪些应用”。

ArgoCD 把部署关系本身变成自定义资源,从而消除这个问题。只需执行 kubectl get application -n argocd,就能看到该集群以何种策略、从哪里获取什么内容并部署到哪里。部署成为对象后,RBAC、审计日志,乃至 GitOps 自身(定义 Application 的 YAML 也提交到仓库)都会自然衔接起来。

工作原理

Application 的骨架由四部分组成。

字段 决定什么
spec.source 从哪里读取——repoURLpathtargetRevision
spec.destination 部署到哪里——server(或 name)、namespace
spec.project 在什么边界内运行——AppProject 名称
spec.syncPolicy 如何对齐——自动化、清理、重试

syncPolicy.automated 包含两个开关。prune 表示“仓库中删除的内容也从集群中删除”,selfHeal 表示“集群与仓库不一致时恢复为仓库状态”。如果两个开关都关闭,ArgoCD 就只是一块在界面上展示差异的仪表板。

syncOptions 用于控制应用方式的细节。CreateNamespace=true 会自动创建目标命名空间;ServerSideApply=true 让服务器跟踪字段所有权,减少多个控制器修改同一对象时的冲突;PruneLast=true 则会先对齐其他资源,最后再执行删除,从而缩小误删事故的影响。

retry 定义失败后的重试方式。通过 limit 以及 backoff 中的 durationfactormaxDuration 构成指数退避。设置 duration: 10sfactor: 2 后,间隔会依次变为 10 秒、20 秒、40 秒,并在 maxDuration 处封顶。以固定间隔无限重试,会变成持续冲击 API 服务器的负载发生器。

顺序控制分为两层。sync wave 通过 argocd.argoproj.io/sync-wave 注解中的数字对资源分组,按较小值优先应用,并等待当前 wave 达到 Healthy 后才进入下一组。同一 wave 内会采用按资源类型划分的默认顺序(Namespace → ConfigMap/Secret → RBAC → CRD → PV/PVC → Service → 工作负载 → Ingress)。在此之上,Hook 会划分整个阶段:PreSyncSyncPostSync,失败时运行 SyncFail。Hook 通常是 Job,通过 argocd.argoproj.io/hook 注解指定,并使用 hook-delete-policy 决定清理时机。默认值为 BeforeHookCreation,所以 Hook 资源成功后仍会保留,直到下一次同步前才删除——正因为这一默认行为,故障后仍能查看失败迁移 Job 的日志。

生产现场中的常见情况

第一,AppProject 是限定事故半径的围栏。 通过 sourceReposdestinationsclusterResourceWhitelistnamespaceResourceBlacklist,可以明确限制“允许从哪些仓库向哪些命名空间部署哪些资源类型”。如果设置 sourceRepos: ["*"],划分项目就失去了意义——一个拼写错误就可能把他人的仓库部署到自己的集群。

第二,无限同步。 HPA 修改 spec.replicas,ArgoCD 将其视为漂移并恢复,HPA 再次修改,ArgoCD 又再次恢复,由此形成循环。必须通过 ignoreDifferences/spec/replicas 排除在比较对象之外才能停止。这里是明确记录由其他控制器拥有的字段不属于 GitOps 所有这一原则的位置。

第三,错误划分 wave 会让部署停在原地。 如果把永远无法达到 Healthy 的资源放在前一个 wave,后面的 wave 将永远不会到来。wave 只应用于“必须提前存在的内容”,并且数量越少越安全。

下一次实验要做什么

从离线包应用 ArgoCD CRD,在集群中注册 ApplicationAppProject 类型,并在 argocd 命名空间中手工编写 Application web。配置自动同步、清理、自我修复开关,以及 syncOptions 和重试退避;再为仓库清单添加 sync wave 与 PreSync Hook。随后使用 AppProject platform 划定边界,把应用归入其中;最后制作配置报告,使其与集群中实际存在的 Application 列表一致。本环境没有 ArgoCD 控制器,因此 Application 不会自行变成 Synced——评分目标是声明是否准确。