|
| 1 | += ADRXXX: Resource Labels and Namespacing |
| 2 | +Sascha Lautenschläger <sascha.lautenschlaeger@stackable.tech> |
| 3 | +v0.1, 2023-08-25 |
| 4 | +:status: accepted |
| 5 | + |
| 6 | +* Status: {status} |
| 7 | +* Contributors: |
| 8 | +** Malte Sander |
| 9 | +** Sebastian Bernauer |
| 10 | +** Sascha Lautenschläger |
| 11 | +** Razvan Mihai |
| 12 | +* Date: 2023-08-25 |
| 13 | +
|
| 14 | +== Context and Problem Statement |
| 15 | + |
| 16 | +This ADR tries to solve a common issue within the SDP. When `stackablectl` (and in the future our Cockpit) deploys |
| 17 | +resources into a Kubernetes cluster, we are currently unable to properly identify them afterwards. Adding a common set |
| 18 | +of labels to the resources we deploy will solve this issue. Additionally we will use namespaces to track resources |
| 19 | +deployed together. The following use-cases are then possible: |
| 20 | + |
| 21 | +* Use-case 1: Uninstalling a demo and stack |
| 22 | +* Use-case 2: Remove/purge all resources deployed by Stackable at once |
| 23 | +* Use-case 3: Stacklet dependency tree (Only needed when decide against a discovery operator, see ...) |
| 24 | +* Use-case 4: Offer users to provide their own custom labels |
| 25 | + |
| 26 | +== Decision Drivers |
| 27 | + |
| 28 | +We want to introduce these common labels, as there is currently no reliable and correct way to determine which resources |
| 29 | +where deployed by one of our management tools. Deciding on a common and structured set of labels will help us to more |
| 30 | +easily manage resources deployed by us. This includes reading, listing, changing and deleting those resources. The |
| 31 | +addition of labels will resolve several long-standing issues in various repositories. |
| 32 | + |
| 33 | +== Considered Options |
| 34 | + |
| 35 | +Kubernetes reserves all labels and annotations in the `kubernetes.io` and `k8s.io` namespaces. See |
| 36 | +https://kubernetes.io/docs/reference/labels-annotations-taints/[here] and |
| 37 | +https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set[here]. |
| 38 | + |
| 39 | +=== Preamble |
| 40 | + |
| 41 | +One general decision we have to make is if we ant to introduce scopes for our label keys. In this context, scope refers |
| 42 | +to one (or more) domain name labels, otherwise known as subdomains. Scopes would allow us to introduce more granular |
| 43 | +(and also grouped) labels. On the other side, we need to consider if we need the added granularity based on the number |
| 44 | +and kind of labels we want to add. In general there are two options: |
| 45 | + |
| 46 | +- `<scope>.stackable.tech/<key>=<value>`, with scope being **one** subdomain |
| 47 | +- `stackable.tech/<key>=<value>`, no scope |
| 48 | + |
| 49 | +=== Labeling all Resources with a Vendor Label |
| 50 | + |
| 51 | +* `app.kubernetes.io/vendor=Stackable`: This is no official well-known label and also violates the reserved namespaces |
| 52 | + above |
| 53 | +* `stackable.tech/vendor=Stackable`: Custom label key prefix, duplicate data |
| 54 | +* `meta.stackable.tech/vendor=Stackable`: Alternative to above, scoped, still duplicated data |
| 55 | + |
| 56 | +It's hard (or impossible) to use a label without any duplicated data. So `stackable.tech/vendor=Stackable` seems like |
| 57 | +a straight-forward and concise option. |
| 58 | + |
| 59 | +''' |
| 60 | + |
| 61 | +A deployed ConfigMap could look like this: |
| 62 | + |
| 63 | +[source,yaml] |
| 64 | +---- |
| 65 | +apiVersion: v1 |
| 66 | +kind: ConfigMap |
| 67 | +metadata: |
| 68 | + name: superset-node-default |
| 69 | +labels: |
| 70 | + app.kubernetes.io/name: superset # reduced set of common labels |
| 71 | + stackable.tech/vendor: Stackable # new vendor label |
| 72 | +data: |
| 73 | +---- |
| 74 | + |
| 75 | +[#ns-labels] |
| 76 | +=== Labeling Resources deployed within a Demo or Stack |
| 77 | + |
| 78 | +* `stackable.tech/stack=<stack-name>`: Attached to all resources deployed by `stackablectl stack install` |
| 79 | +* `stackable.tech/demo=<demo-name>`: Attached to all resources deployed by `stackablectl demo install` |
| 80 | + |
| 81 | +Alternatives to above are: |
| 82 | + |
| 83 | +* `resources.stackable.tech/<stack|demo>=<stack-name|demo-name>` |
| 84 | +* `meta.stackable.tech/<stack|demo>=<stack-name|demo-name>` |
| 85 | +* `res.stackable.tech/<stack|demo>=<stack-name|demo-name>` |
| 86 | + |
| 87 | +Both `<stack-name>` and `<demo-name>` will be replaced by the selected stack or demo name. We need to make sure that |
| 88 | +this value doesn't exceed the maximum length of 63 characters. If the name is too long, we have three options: |
| 89 | + |
| 90 | +* Hard error out, the installation is canceled (Not recommended because stack and demo names are chosen by us) |
| 91 | +* We automatically truncate the name to the maximum length: `a-way-too-long-name` becomes `a-way-too-lo<EOL>` |
| 92 | +* We automatically truncate the name and add a random suffix: `a-way-too-long-name` becomes `a-way-a1b2c3<EOL>` |
| 93 | + |
| 94 | +''' |
| 95 | + |
| 96 | +A deployed ConfigMap (by running `stackablectl demo install`) could look like this. Notice that resources part of a demo |
| 97 | +**and** a stack include labels for both of these scopes. |
| 98 | + |
| 99 | +[source,yaml] |
| 100 | +---- |
| 101 | +apiVersion: v1 |
| 102 | +kind: ConfigMap |
| 103 | +metadata: |
| 104 | + name: superset-node-default |
| 105 | +labels: |
| 106 | + app.kubernetes.io/name: superset # reduced set of common labels |
| 107 | + stackable.tech/vendor: Stackable |
| 108 | + stackable.tech/stack: nifi-kafka-druid-superset-s3 # new stack label |
| 109 | + stackable.tech/demo: nifi-kafka-druid-water-level-data # new demo label |
| 110 | +data: |
| 111 | +---- |
| 112 | + |
| 113 | +=== Namespacing Stacks and Demos |
| 114 | + |
| 115 | +Considered default values for above labels are: |
| 116 | + |
| 117 | +* `stackable-<demo|stack>-<demo-name|stack-name>(-suffix)`: Clearly indicates this namespace belongs to the SDP, we |
| 118 | + might run into length limits |
| 119 | +* `<demo|stack>-<demo-name|stack-name>(-suffix)`: Less likely we will run into length limits, but we loose the clear |
| 120 | + indication this namespace belongs to the SDP. |
| 121 | + |
| 122 | +We need to perform length and character validation for these namespace names. There are two possible paths: |
| 123 | + |
| 124 | +* If the user *doesn't* provide a custom namespace, we need to make sure that the value doesn't exceed it's maximum |
| 125 | + length when the stack or demo names are inserted. Truncate the name if needed. |
| 126 | +* If the user *does* provide a custom namespace, we need to make sure that the custom namespace length doesn't exceed |
| 127 | + it's maximum length. Don't automatically truncate, instead return an error explaining the user needs to shorten the |
| 128 | + namespace name. |
| 129 | + |
| 130 | +The maximum length for both cases is 63 characters. |
| 131 | + |
| 132 | +=== Adding Label to indicate which Management Tool was used |
| 133 | + |
| 134 | +The following options are available: |
| 135 | + |
| 136 | +* `app.kubernetes.io/managed-by=stackablectl|stackable-cockpit`: Well-known label, however not recommended because Helm |
| 137 | + already uses this label to track which resources are managed by Helm. As we use Helm in the background to install some |
| 138 | + of our manifests, we would potentially break Helms (uninstall) behavior. |
| 139 | +* `stackable.tech/managed-by=stackablectl|stackable-cockpit`: Doesn't collide with Helm |
| 140 | +* `stackable.tech/deployed-by=stackablectl|stackable-cockpit`: Alternative to above |
| 141 | + |
| 142 | +Alternatives are: |
| 143 | + |
| 144 | +* `management.stackable.tech/managed-by=stackablectl|stackable-cockpit` |
| 145 | +* `tools.stackable.tech/managed-by=stackablectl|stackable-cockpit` |
| 146 | +* `mgmt.stackable.tech/managed-by=stackablectl|stackable-cockpit` |
| 147 | + |
| 148 | +''' |
| 149 | + |
| 150 | +A deployed ConfigMap could look like this.: |
| 151 | + |
| 152 | +[source,yaml] |
| 153 | +---- |
| 154 | +apiVersion: v1 |
| 155 | +kind: ConfigMap |
| 156 | +metadata: |
| 157 | + name: superset-node-default |
| 158 | +labels: |
| 159 | + app.kubernetes.io/name: superset # reduced set of common labels |
| 160 | + stackable.tech/vendor: Stackable |
| 161 | + stackable.tech/managed-by: stackablectl # new management tool label |
| 162 | +data: |
| 163 | +---- |
| 164 | + |
| 165 | +=== Enabling Custom Labels provided by Users |
| 166 | + |
| 167 | +When providing support for user-controlled custom labels, we need to think about the degree of freedom we want to |
| 168 | +support. Possible levels where custom labels could be attached are: cluster, role, and role group level. We also need |
| 169 | +to make sure the custom user-provided labels don't collide with our labels. We can either: |
| 170 | + |
| 171 | +* print out a warning and don't apply the invalid label(s) |
| 172 | +* hard-error and bail |
| 173 | + |
| 174 | +==== Option 1 - Cluster Level Labels |
| 175 | + |
| 176 | +[source,yaml] |
| 177 | +---- |
| 178 | +--- |
| 179 | +apiVersion: example.stackable.tech/v1alpha1 |
| 180 | +kind: ExampleCluster |
| 181 | +metadata: |
| 182 | + name: example |
| 183 | +spec: |
| 184 | + clusterConfig: |
| 185 | + labels: |
| 186 | + foo: bar |
| 187 | + baz: foo |
| 188 | +---- |
| 189 | + |
| 190 | +==== Option 2 - Role (and Role Group) Level Labels |
| 191 | + |
| 192 | +[source,yaml] |
| 193 | +---- |
| 194 | +--- |
| 195 | +apiVersion: example.stackable.tech/v1alpha1 |
| 196 | +kind: ExampleCluster |
| 197 | +metadata: |
| 198 | + name: example |
| 199 | + labels: |
| 200 | + foo: bar |
| 201 | + baz: foo |
| 202 | +spec: |
| 203 | +---- |
| 204 | + |
| 205 | +==== Option 3 - Only Role Level Labels |
| 206 | + |
| 207 | +This option is highly dependant on the outcome of the PodDisruptionBudget ADR. This options requires the introduction |
| 208 | +of `roleGroup` discussed in the mentioned ADR. |
| 209 | + |
| 210 | +[source,yaml] |
| 211 | +---- |
| 212 | +--- |
| 213 | +apiVersion: example.stackable.tech/v1alpha1 |
| 214 | +kind: ExampleCluster |
| 215 | +metadata: |
| 216 | + name: example |
| 217 | +spec: |
| 218 | + roleConfig: |
| 219 | + labels: |
| 220 | + foo: bar |
| 221 | + baz: foo |
| 222 | +---- |
| 223 | + |
| 224 | +==== Option 4 - Leave as is |
| 225 | + |
| 226 | +Continue to use `podOverrides`. Don't introduce dedicated support for labels using above mentioned options 1-3. |
| 227 | + |
| 228 | +== Thoughts on the Implementation |
| 229 | + |
| 230 | +=== General Notes |
| 231 | + |
| 232 | +* Each stack/demo will be deployed into its own namespace. This enables `stackablectl demo installed` |
| 233 | +* Each namespace has a label attached, see xref:#ns-labels[above]. |
| 234 | + |
| 235 | +=== `stackablectl demo install <name>` |
| 236 | + |
| 237 | +[source] |
| 238 | +---- |
| 239 | +if -n set { |
| 240 | + if ns exists -> Error or propose different ns |
| 241 | +} else { |
| 242 | + if ns exists { |
| 243 | + echo "Already installed. Install again?" |
| 244 | + ns += suffix |
| 245 | + } |
| 246 | +} |
| 247 | +
|
| 248 | +if demo/stack not supports ns { |
| 249 | + return Error |
| 250 | +} |
| 251 | +
|
| 252 | +if ns not exists { |
| 253 | + create_ns_with_label() |
| 254 | +} |
| 255 | +
|
| 256 | +template_plain_yaml_cluster_scope() |
| 257 | +
|
| 258 | +install_demo() |
| 259 | +---- |
| 260 | + |
| 261 | +=== `stackablectl demo uninstall <name>` |
| 262 | + |
| 263 | +[source] |
| 264 | +---- |
| 265 | +for chart in helmCharts.reverse() { |
| 266 | + chart.uninstall() |
| 267 | +} |
| 268 | +
|
| 269 | +// AuthClass, SecretClass, ClusterRole, ClusterRoleBinding, etc... |
| 270 | +delete_resources_with_label() |
| 271 | +
|
| 272 | +// Also deletes PVCs, operators are not uninstalled |
| 273 | +delete_ns_with_label() |
| 274 | +---- |
| 275 | + |
| 276 | +=== `stackablectl demo installed` |
| 277 | + |
| 278 | +[source] |
| 279 | +---- |
| 280 | +for demo in demos_with_label("demo-*") { |
| 281 | + echo demo |
| 282 | +} |
| 283 | +---- |
| 284 | + |
| 285 | +== Results |
| 286 | + |
| 287 | +* **Scope:** Do not use scopes for now. Add it in the future if needed. |
| 288 | +* **Labeling all Resources with a Vendor Label:** Yes, use `stackable.tech/vendor=Stackable` |
| 289 | +* **Labeling Resources deployed within a Demo or Stack:** Yes, use `stackable-<demo|stack>-<demo-name|stack-name>(-suffix)` |
| 290 | + with `suffix` being optional and the implementation not yet decided on. |
| 291 | +* **Namespacing Stacks and Demos:** Yes, use `stackable-<demo|stack>-<demo-name|stack-name>(-suffix)` |
| 292 | +* **Adding Label to indicate which Management Tool was used:** Yes, use |
| 293 | + `stackable.tech/managed-by=stackablectl|stackable-cockpit` |
| 294 | +* **Enabling Custom Labels provided by Users:** No support for now. Add it in the future if this feature is requested. |
0 commit comments