造出租户边界与应用工厂
目标
通过 AppProject 声明 tenant 边界,编写使用两种 ApplicationSet 生成 Application 的 manifest,并把与该边界相对应的实际 namespace 和 ResourceQuota 部署到 cluster。
为什么重要
multi-tenancy 由两层组成。上层规定“谁可以声明什么”,下层规定“这些声明能使用多少资源”。AppProject 只负责上层。即使通过 destinations 限制了部署目标,也无法阻止该 namespace 占满 node,这属于 ResourceQuota 的职责。反过来,如果只有 ResourceQuota,就无法阻止 tenant 把别人的仓库作为 source,或创建 ClusterRoleBinding。只有把两层一起建立起来,才能真正理解每种工具的作用范围。
步骤
- 创建
/root/capa-project/目录,并在appproject.yaml中写入 kindAppProject、metadata.name为capa-tenants、metadata.namespace为argocd。在spec.sourceRepos中加入https://gitea.homelab.internal/platform/*;在spec.destinations[0]中加入 serverhttps://kubernetes.default.svc与 namespacecapa-team-*。 - 在同一文件的
spec.clusterResourceWhitelist中加入 group""、kindNamespace;在spec.namespaceResourceBlacklist中加入 group""的ResourceQuota和LimitRange两种资源。 - 在
spec.roles[0]中设置 namedeployer,policies 包含p, proj:capa-tenants:deployer, applications, sync, capa-tenants/*, allow,groups 中加入capa-platform。 - 在
spec.syncWindows中创建一项:kinddeny、schedule0 0 * * 0,6、duration24h、applications*。 - 在
/root/capa-project/appset-list.yaml中写入 kindApplicationSet、metadata.name为capa-tenants-list,并把spec.goTemplate设为true。在spec.generators[0].list.elements中加入 3 项,每项的tenant值分别为alpha、bravo、charlie;把spec.template.spec.project指定为capa-tenants。 - 在
/root/capa-project/appset-matrix.yaml中写入 kindApplicationSet、metadata.name为capa-tenants-matrix,并把spec.goTemplate设为true。在spec.generators[0].matrix.generators中恰好放入两个 generator:一个是 repoURL 为https://gitea.homelab.internal/platform/tenants.git且directories[0].path为apps/*的 git generator;另一个是至少包含一个 element 的 list generator。 - 在 cluster 中实际创建
capa-team-alpha、capa-team-bravo、capa-team-charlie三个 namespace,并分别把 labelcapa.io/tenant的值设为alpha、bravo、charlie。 - 在三个 namespace 中分别实际创建名为
tenant-quota的 ResourceQuota。spec.hard.pods为10,spec.hard["requests.cpu"]为2。
参考
- 可使用
kubectl create quota tenant-quota --hard=pods=10,requests.cpu=2 -n <네임스페이스>快速创建。 - 验证 manifest 时,可像
yq '.spec.clusterResourceWhitelist' /root/capa-project/appproject.yaml一样只提取目标字段。 - 常见错误 1:在 whitelist 与 blacklist 中加入相同资源。两个字段的 scope 不同。
- 常见错误 2:matrix 下只放一个 generator。只有两个 generator 才能形成笛卡尔积。
配置 AppProject 的允许 source 与部署目标
创建 /root/capa-project/ 目录,并在 appproject.yaml 中写入 kind AppProject、metadata.name 为 capa-tenants、metadata.namespace 为 argocd。在 spec.sourceRepos 中加入 https://gitea.homelab.internal/platform/*;在 spec.destinations[0] 中加入 server https://kubernetes.default.svc 与 namespace capa-team-*。
sourceRepos 与 destinations 都是 allowlist。destinations 的 namespace 字段可以使用 wildcard。
配置 whitelist 与 blacklist
在同一文件的 spec.clusterResourceWhitelist 中加入 group ""、kind Namespace;在 spec.namespaceResourceBlacklist 中加入 group "" 的 ResourceQuota 和 LimitRange 两种资源。
cluster scope 默认为全部禁止,需要列出允许项;namespace scope 默认为全部允许,需要列出禁止项。记住两者方向相反即可。
映射 project role 与 group
在 spec.roles[0] 中设置 name deployer,policies 包含 p, proj:capa-tenants:deployer, applications, sync, capa-tenants/*, allow,groups 中加入 capa-platform。
policy 字符串由 p、SUBJECT、RESOURCE、ACTION、OBJECT、EFFECT 六部分组成。project role 的 subject 使用 proj:项目名:角色名格式。
在周末禁止同步
在 spec.syncWindows 中创建一项:kind deny、schedule 0 0 * * 0,6、duration 24h、applications *。
syncWindows 项由 kind、schedule、duration、applications 组成。schedule 表示窗口开始时间的 cron,duration 表示窗口长度。
配置 list generator 与 goTemplate
在 /root/capa-project/appset-list.yaml 中写入 kind ApplicationSet、metadata.name 为 capa-tenants-list,并把 spec.goTemplate 设为 true。在 spec.generators[0].list.elements 中加入 3 项,每项的 tenant 值分别为 alpha、bravo、charlie;把 spec.template.spec.project 指定为 capa-tenants。
list generator 的 elements 是由任意 key 组成的 map 数组。若要使用条件或循环,需要在 spec 下启用一个用于切换 template engine 的 boolean。
通过 matrix generator 创建笛卡尔积
在 /root/capa-project/appset-matrix.yaml 中写入 kind ApplicationSet、metadata.name 为 capa-tenants-matrix,并把 spec.goTemplate 设为 true。在 spec.generators[0].matrix.generators 中恰好放入两个 generator:一个是 repoURL 为 https://gitea.homelab.internal/platform/tenants.git 且 directories[0].path 为 apps/* 的 git generator;另一个是至少包含一个 element 的 list generator。
matrix 下必须恰好有两个 generators 才会形成笛卡尔积。git generator 通过 directories 扫描目录,并为每个目录产生一组参数。
创建三个 tenant namespace
在 cluster 中实际创建 capa-team-alpha、capa-team-bravo、capa-team-charlie 三个 namespace,并分别把 label capa.io/tenant 的值设为 alpha、bravo、charlie。
从这里开始操作的是实际 cluster。确保名称与 label 值一一对应;这是重复操作,也可以使用 shell loop。
用 ResourceQuota 建立资源边界
在三个 namespace 中分别实际创建名为 tenant-quota 的 ResourceQuota。spec.hard.pods 为 10,spec.hard["requests.cpu"] 为 2。
ResourceQuota 的 spec.hard 是 map,key 中包含点号。请记住,AppProject 画出的只是声明层面的边界,这正是本步骤存在的意义。