LabHub
学习 学习路径 课程

CAPA — Argo 项目认证助理

白名单和黑名单的方向是反的

在 LabHub 中继续学习

一句话总结

AppProject 是规定“团队能从哪里获取内容、能把内容部署到哪里”的边界;ApplicationSet 则是在该边界内批量生成 Application 的工厂。AppProject 最常出错之处,是集群资源使用白名单(只允许列出的内容),而命名空间资源使用黑名单(只禁止列出的内容),两个字段方向相反。

概念图: 一句话总结 · 为什么需要它 · 如何运作 · 现场常见情况

为什么需要它

Argo CD 只有一个团队时,default 项目就够用。团队增加到三个后,问题随之出现:A 团队误把应用部署到 B 团队的命名空间怎么办?有人把个人 GitHub 仓库注册为来源怎么办?应用创建 ClusterRoleBinding,让自己成为 cluster-admin 怎么办?仅靠 RBAC 无法阻止这些情况。Argo CD 的服务账号本来就拥有较强权限,用户实际上是通过 Argo CD 借用这些权限。因此 Argo CD 会在自己的层级再次过滤,这层过滤网就是 AppProject。

ApplicationSet 源于另一种痛点。如果有五个集群和二十个服务,就需要一百个 Application,无法手工管理;每增加一个集群,还要复制二十份。生成器把这些重复操作转换成数据。

如何运作

必须连同方向一起记住 AppProject 的核心字段。

字段 方向 含义
sourceRepos 允许列表 只能使用匹配这里所列模式的仓库作为来源
destinations 允许列表 只能部署到这里所列的集群和命名空间
clusterResourceWhitelist 允许列表 只能创建这里所列的集群作用域资源种类
namespaceResourceBlacklist 禁止列表 只有这里所列的命名空间作用域资源种类不能创建

第三项和第四项方向相反。集群资源默认全部禁止,因此只列出 Namespace 就只开放 Namespace。命名空间资源默认全部允许,因此列出 ResourceQuota 就只关闭 ResourceQuota。若混淆方向,就会出现“以为已经禁止,实际却开放”的状态,比没有策略更危险。

syncWindows 按时段开放或关闭同步。只需记住一个规则:deny 优先于 allow。如果工作日办公时段的 allow 与周末 deny 重叠,重叠区间仍然禁止。设置 manualSync: true 后,该窗口内会禁止自动同步,只允许人工触发。

ApplicationSet 的基础生成器包括 list(静态列表)、clusters(已注册集群)、git(扫描目录或读取文件)、pullRequest(PR 预览)和 scmProvider(自动发现组织仓库),并可搭配两类组合器。matrix 是两个生成器的笛卡尔积,三个集群和四个应用会生成十二项。merge 则通过 mergeKeys 连接,并覆盖键相同项目的值。先设置所有集群的公共值,再为特定集群提供不同值时,应使用 merge。

默认模板引擎是 fasttemplate,只能替换变量。如果需要条件或循环,必须启用 spec.goTemplate: true;启用后,引用语法也会变成带点的形式。在 goTemplateOptions 中设置 missingkey=error,可以让缺失键直接报错,而不是悄悄变成空字符串,从而防止生成名称为空的 Application。

app-of-apps 是让一个 Application 指向包含其他 Application 的目录的模式。它可以通过一次引导启动整个平台;但删除父应用时,所有子应用都会成为 prune 目标,因此尤其要谨慎设置父应用的 prune。

现场常见情况

作者的家庭实验室只有一个集群,但通过命名空间划分租户。这里的经验是,AppProject 描绘的边界与实际资源边界是两回事。AppProject 的 destinations 只是语法层面的许可,表示“可以部署到 capa-team-alpha”,完全不控制该命名空间能消耗多少节点资源。资源边界由 ResourceQuota 和 LimitRange 建立。这也解释了为何在 AppProject 的 namespaceResourceBlacklist 中加入 ResourceQuota 是标准做法:如果租户可以自行提高配额,配额就失去了意义。平台团队负责创建配额,租户不能修改,这正是两个字段结合后的效果。

对于混有 GPU 节点的集群,还要更进一步。GPU Feature Discovery 添加的标签是字符串,无法使用“24GB 以上”这类比较选择器,因此应给节点手工添加 gpu.homelab/tier 之类的语义标签,让工作负载选择适合自己的等级。把这类标签值按租户放入 ApplicationSet 的 list 生成器后,就能用同一个模板生成部署到不同节点组的应用。

下一次实验要做什么

在 /root/capa-project/ 中编写一个 AppProject 和两个 ApplicationSet(list 生成器、matrix 生成器),并把该项目允许的三个租户命名空间及各自的 ResourceQuota 真正部署到集群中,将语法边界与资源边界并排建立起来。