|
| 1 | += ArgoCD multi-tenancy |
| 2 | + |
| 3 | +Project Syn allows users to assign Commodore components installed on a cluster to multiple teams. |
| 4 | +The original design of this feature is documented in xref:SDDs:0030-argocd-multitenancy.adoc[]. |
| 5 | + |
| 6 | +== Configuration |
| 7 | + |
| 8 | +The assignment of components to teams is controlled via inventory parameter `syn`. |
| 9 | +In particular, parameters `syn.owner` and `syn.teams` describe which team is responsible for which component. |
| 10 | + |
| 11 | +Each component instance on a cluster must be assigned to exactly one team. |
| 12 | +To explicitly assign an instance to a team, the instance name is added to `syn.teams.<team>.instances`. |
| 13 | +Instances can be removed from `syn.teams.<team>.instances` by adding the instance name prefixed with `~` footnote:[The SDD requires that consumers of the instance list apply xref:commodore:ROOT:reference/commodore-libjsonnet.adoc#_renderarrayarr[`com.renderArray()`]] on the list. |
| 14 | + |
| 15 | +NOTE: The https://github.com/projectsyn/jsonnet-libs/blob/main/syn-teams.libsonnet[`syn-teams.libsonnet`] Jsonnet library exposes fields which provide rendered views of the team to instance and instance to team mappings. |
| 16 | + |
| 17 | +Any instance that's not explicitly assigned to a team is assigned to the cluster's owner team which is indicated by parameter `syn.owner`. |
| 18 | + |
| 19 | +NOTE: To assign instance-aware components which deploy all instances through a single ArgoCD application to a non-owner team, the component name must be added to `syn.teams.<team>.instances` in order to assign the application to that team. |
| 20 | + |
| 21 | +== Implementation |
| 22 | + |
| 23 | +Project Syn implements ArgoCD multi-tenancy by deploying an independent ArgoCD project and root application footnote:[Project Syn uses the term "root application" for ArgoCD's https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#app-of-apps[app of apps] concept.] for each team that's responsible for at least one component present on the cluster. |
| 24 | + |
| 25 | +Instances assigned to the cluster's owner team remain assigned to ArgoCD project `syn` and root application `root`. |
| 26 | +This project and root application are always present on a Project Syn-managed cluster regardless of whether `syn.owner` is set. |
| 27 | + |
| 28 | +For each additional team that's responsible for one or more component instances on the cluster, a project called `<team-name>` and a root application called `root-<team-name>` are present on the cluster. |
| 29 | + |
| 30 | +To ensure that each project and root application are fully independent, each root application reads ArgoCD application manifests from a different path in the cluster catalog. |
| 31 | +The default root application reads manifests from catalog path `apps/`. |
| 32 | +All other root applications read manifests from catalog path `apps-<team-name>/`. |
| 33 | + |
| 34 | +Additional projects and root applications are bootstrapped by Steward based on the list of team names present in a config map (by default `additional-root-apps`). |
| 35 | +Steward reads this config map once a minute and ensures that an ArgoCD project and root app exist for each team. |
| 36 | + |
| 37 | +The ArgoCD component dynamically sets `spec.project` of ArgoCD application manifests by treating `.metadata.name` of the manifest as a component instance name and looking up the responsible team for that instance through the `syn-teams.libsonnet` Jsonnet library. |
| 38 | + |
| 39 | +NOTE: The ArgoCD component library assumes that each ArgoCD application's `metadata.name` is set to either a component name or a component instance name. |
| 40 | + |
| 41 | +To ease the transition to the multi-tenancy model, Commodore components need to be explicitly marked as multi-tenant aware by setting the component parameter `_metadata.multi_tenant` to `true`. |
| 42 | +The ArgoCD commodore component will raise an error if a component which isn't marked as multi-tenant-aware is assigned to a team other than the cluster's owner team. |
| 43 | + |
| 44 | +[IMPORTANT] |
| 45 | +==== |
| 46 | +Components that set `_metadata.multi_tenant=true` are responsible for making sure that they write their ArgoCD application manifests into the appropriate catalog path. |
| 47 | +
|
| 48 | +The ArgoCD component ensures that `spec.project` of an application manifest generated by the `argocd.libjsonnet` component library will be set to the responsible team's ArgoCD project. |
| 49 | +As noted above, each non-owner team's ArgoCD project is called `<team-name>`. |
| 50 | +This allows components to make sure that the application manifests are written to the correct catalog path by setting `output_path: .` for the Kapitan compile step for `component/app.jsonnet` and by rendering each application's output key based on the application's `spec.project`. |
| 51 | +
|
| 52 | +.`class/component.yml` |
| 53 | +[source,yaml] |
| 54 | +---- |
| 55 | +parameters: |
| 56 | + kapitan: |
| 57 | + compile: |
| 58 | + - input_paths: |
| 59 | + - ${_instance}/component/app.jsonnet |
| 60 | + input_type: jsonnet |
| 61 | + output_path: apps/ |
| 62 | + output_path: . |
| 63 | +---- |
| 64 | +
|
| 65 | +.`component/app.jsonnet` |
| 66 | +[source,jsonnet] |
| 67 | +---- |
| 68 | +local kap = import 'lib/kapitan.libjsonnet'; |
| 69 | +local kube = import 'lib/kube.libjsonnet'; |
| 70 | +local inv = kap.inventory(); |
| 71 | +local params = inv.parameters.<component>; <1> |
| 72 | +local argocd = import 'lib/argocd.libjsonnet'; |
| 73 | +
|
| 74 | +local app = argocd.App(<component>, params.namespace, secrets=true); <1> |
| 75 | +
|
| 76 | +local appPath = |
| 77 | + local project = std.get(app, 'spec', { project: 'syn' }).project; <2> |
| 78 | + if project == 'syn' then 'apps' else 'apps-%s' % project; |
| 79 | +
|
| 80 | +{ |
| 81 | + ['%s/<component>' % appPath]: app, <1> |
| 82 | +} |
| 83 | +---- |
| 84 | +<1> Replace `<component> with the component's name. |
| 85 | +<2> We use `std.get()` to read `spec.project` because `commodore component compile` currently uses a fake `argocd.libjsonnet` which doesn't generate a valid ArgoCD application manifest. |
| 86 | +==== |
| 87 | + |
| 88 | +In order to enable users to easily move ownership of existing component instances, Steward and the ArgoCD Commodore component ensure that resource pruning is disabled for each root application. |
| 89 | + |
| 90 | +NOTE: Without this configuration, there's a chance that a component instance would be deleted and recreated when it's transferred to a different team. |
| 91 | + |
| 92 | +== Usage in Commodore components |
| 93 | + |
| 94 | +Commodore components that want to use the component team ownership information should use the `syn-teams.libsonnet` Jsonnet library which provides the ownership information in a variety of ways. |
| 95 | + |
| 96 | +This library is available on https://github.com/projectsyn/jsonnet-libs[GitHub] and can be included as a regular component Jsonnet dependency: |
| 97 | + |
| 98 | +.jsonnetfile.json |
| 99 | +[source,json] |
| 100 | +---- |
| 101 | +{ |
| 102 | + "version": 1, |
| 103 | + "dependencies": [ |
| 104 | + { |
| 105 | + "source": { |
| 106 | + "git": { |
| 107 | + "remote": "https://github.com/projectsyn/jsonnet-libs", |
| 108 | + "subdir": "" |
| 109 | + } |
| 110 | + }, |
| 111 | + "version": "main", |
| 112 | + "name": "syn" |
| 113 | + } |
| 114 | + ], |
| 115 | + "legacyImports": true |
| 116 | +} |
| 117 | +---- |
| 118 | + |
| 119 | +Users should check the library for usage documentation. |
0 commit comments