sigs.k8s.io/cluster-api@v1.7.1/docs/proposals/20200220-cluster-resource-set.md (about) 1 --- 2 title: ClusterResourceSet 3 authors: 4 - "@sedefsavas" 5 reviewers: 6 - "@vincepri" 7 - "@detiber" 8 - "@ncdc" 9 - "@fabriziopandini" 10 creation-date: 2020-02-20 11 last-updated: 2020-08-05 12 status: experimental 13 --- 14 15 # ClusterResourceSet 16 17 ## Table of Contents 18 19 <!-- START doctoc generated TOC please keep comment here to allow auto update --> 20 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> 21 22 - [Glossary](#glossary) 23 - [Summary](#summary) 24 - [Motivation](#motivation) 25 - [Goals](#goals) 26 - [Non-Goals/Future Work](#non-goalsfuture-work) 27 - [Proposal](#proposal) 28 - [User Stories](#user-stories) 29 - [Story 1](#story-1) 30 - [Story 2](#story-2) 31 - [Story 3](#story-3) 32 - [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints) 33 - [Data model changes to existing API types](#data-model-changes-to-existing-api-types) 34 - [ClusterResourceSet Object Definition](#clusterresourceset-object-definition) 35 - [ClusterResourceSetBinding Object Definition](#clusterresourcesetbinding-object-definition) 36 - [`ApplyOnce` mode](#applyonce-mode) 37 - [`Reconcile` mode](#reconcile-mode) 38 - [Risks and Mitigations](#risks-and-mitigations) 39 - [Drift](#drift) 40 - [Deletion](#deletion) 41 - [Alternatives](#alternatives) 42 - [Upgrade Strategy](#upgrade-strategy) 43 - [Additional Details](#additional-details) 44 - [Test Plan [optional]](#test-plan-optional) 45 - [Graduation Criteria [optional]](#graduation-criteria-optional) 46 - [Implementation History](#implementation-history) 47 48 <!-- END doctoc generated TOC please keep comment here to allow auto update --> 49 50 ## Glossary 51 52 Refer to the [Cluster API Book Glossary](https://cluster-api.sigs.k8s.io/reference/glossary.html). 53 54 ## Summary 55 56 Provide a mechanism for applying resources in a cluster once it is created. 57 58 ## Motivation 59 60 Clusters created by Cluster API are minimally functional. For instance,they do not have a container networking interface (CNI), which is required for pod-to-pod networking, or any StorageClasses, which are required for dynamic persistent volume provisioning. 61 Users today must manually add these components to every cluster they create. 62 63 Having a mechanism to apply an initial set of default resources after clusters are created makes clusters created with Cluster API functional and ready for workloads from the beginning, without requiring additional user intervention. 64 65 To achieve this, ClusterResourceSet CRD is introduced that will be responsible for applying a set resources defined by users to the matching clusters (`label selectors` will be used to select clusters that the ClusterResourceSet resources will applied to.) 66 67 68 ### Goals 69 70 - Provide a means to specify a set of resources to apply automatically to newly-created and existing Clusters. Resources will be reapplied when their definition changes. 71 - Support additions to the resource list by applying the new added resources to both new and existing matching clusters. 72 - Provide a way to see which ClusterResourceSets are applied to a particular cluster using a new CRD, `ClusterResourceSetBinding`. 73 - Support both json and yaml resources. 74 75 ### Non-Goals/Future Work 76 77 - Replace or compete with the Cluster Addons subproject. 78 - Support deletion of resources from clusters. Deleting a resource from a ClusterResourceSet or deleting a ClusterResourceSet does not result in deletion of those resources from clusters. 79 - Lifecycle management of the installed resources (such as CNI). 80 81 82 ## Proposal 83 84 ### User Stories 85 86 #### Story 1 87 88 As someone creating multiple clusters, I want some/all my clusters to have a CNI provider of my choosing installed automatically, so I don’t have to manually repeat the installation for each new cluster. 89 90 #### Story 2 91 92 As someone creating multiple clusters, I want some/all my clusters to have a StorageClass installed automatically, so I don't have to manually repeat the installation for each new cluster. 93 94 #### Story 3 95 96 As someone creating multiple clusters and using ClusterResourceSet to install some resources, I want to see which resources are applied to my clusters, when they are applied, and if applied successfully. 97 98 ### Implementation Details/Notes/Constraints 99 100 #### Data model changes to existing API types 101 102 None. We are planning to implement this feature without modifying any of the existing structure to minimize the footprint of ClusterResourceSet Controller. This enhancement will follow Kubernetes’s feature-gate structure and will be under the experimental package with its APIs, and enabled/disabled with a feature gate. 103 104 #### ClusterResourceSet Object Definition 105 106 This is the CRD that has a set of components (resources) to be applied to clusters that match the label selector in it. The label selector cannot be empty. 107 108 The resources field is a list of `Secrets`/`ConfigMaps` which should be in the same namespace with `ClusterResourceSet`. The clusterSelector field is a Kubernetes [label selector](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements) that matches against labels on clusters (only the clusters in the same namespace with the ClusterResourceSet resource). 109 ClusterResourceSet is namespace-scoped, all resources and clusters needs to be in the same namespace as the ClusterResourceSet. 110 *Sample ClusterResourceSet YAML* 111 112 ```yaml 113 --- 114 apiVersion: addons.cluster.x-k8s.io/v1alpha3 115 kind: ClusterResourceSet 116 metadata: 117 name: crs1 118 namespace: default 119 spec: 120 mode: "ApplyOnce" 121 clusterSelector: 122 matchLabels: 123 cni: calico 124 resources: 125 - name: db-secret 126 kind: Secret 127 - name: calico-addon 128 kind: ConfigMap 129 ``` 130 131 The supported modes will be: 132 * `ApplyOnce`. This will be the default mode if no mode is provided. Resources are only applied once. 133 * `Reconcile`. Resources are reapplied when the content of the `ConfigMap` or `Secret` that defines them changes. 134 135 If ClusterResourceSet resources will be managed by an operator after they are applied by ClusterResourceSet controller, "ApplyOnce" mode must be used so that reconciliation on those resources can be delegated to the operator. 136 137 Each item in the resources specifies a kind (must be either ConfigMap or Secret) and a name. Each referenced ConfigMap/Secret contains yaml/json content as value. 138 `ClusterResourceSet` object will be added as owner to its resources. 139 140 ***Secrets as Resources*** 141 142 Both `Secrets` and `ConfigMaps` `data` fields can be a list of key-value pairs. Any key is acceptable, and as value, there can be multiple objects in yaml or json format. 143 144 For preventing all secrets to be reached by all clusters in a namespace, only secrets with type `addons.cluster.x-k8s.io/resource-set` can be accessed by ClusterResourceSet controller. 145 Secrets are preferred if the data includes sensitive information. 146 147 An easy way to create resource `Secrets` is to have a yaml or json file with the components. 148 149 E.g., this is `db.yaml` that has multiple objects: 150 ``` 151 kind: Secret 152 apiVersion: v1 153 metadata: 154 name: mysql-access 155 namespace: system 156 --- 157 kind: ClusterRole 158 apiVersion: rbac.authorization.k8s.io/v1 159 metadata: 160 name: db-admin 161 namespace: system 162 ``` 163 164 We can create a secret that has these components in its data field to be used in `ClusterResourceSet`: 165 166 ` #kubectl create secret generic db-secret --from-file=db.yaml --type=addons.cluster.x-k8s.io/resource-set` 167 168 ```yaml 169 apiVersion: v1 170 kind: Secret 171 metadata: 172 name: db-secret 173 type: addons.cluster.x-k8s.io/resource-set 174 stringData: 175 db.yaml: |- 176 kind: Secret 177 apiVersion: v1 178 metadata: 179 name: mysql-access 180 namespace: system 181 --- 182 kind: ClusterRole 183 apiVersion: rbac.authorization.k8s.io/v1 184 metadata: 185 name: db-admin 186 namespace: system 187 ``` 188 189 ***ConfigMaps as Resources*** 190 191 Similar to `Secrets`, `ConfigMaps` can be created using a yaml/json file: `kubectl create configmap calico-addon --from-file=calico1.yaml,calico2.yaml` 192 Multiple keys in the data field and then multiple objects in each value are supported. 193 ```yaml 194 apiVersion: v1 195 kind: ConfigMap 196 metadata: 197 name: calico-addon 198 data: 199 calico1.yaml: |- 200 kind: Secret 201 apiVersion: v1 202 metadata: 203 name: calico-secret1 204 namespace: mysecrets 205 --- 206 kind: Secret 207 apiVersion: v1 208 metadata: 209 name: calico-secret2 210 namespace: mysecrets 211 calico2.yaml: |- 212 kind: ConfigMap 213 apiVersion: v1 214 metadata: 215 name: calico-configmap 216 namespace: myconfigmaps 217 ``` 218 219 #### ClusterResourceSetBinding Object Definition 220 The resources in `ClusterResourceSet` will be applied to matching clusters. 221 There is many-to-many mapping between Clusters and `ClusterResourceSets`: Multiple `ClusterResourceSets` can match with a cluster; and multiple clusters can match with a single `ClusterResourceSet`. 222 To keep information on which resources applied to which clusters, a new CRD is used, `ClusterResourceSetBinding` will be created in the management cluster. There will be one `ClusterResourceSetBinding` per workload cluster. 223 ClusterResourceBinding's name will be same with the `Cluster` name. Both `Cluster` and the matching `ClusterResourceSets` will be added as owners to the ClusterResourceBinding. 224 225 Example `ClusterResourceBinding` object: 226 ```yaml 227 apiVersion: v1 228 kind: ClusterResourceBinding 229 metadata: 230 name: <cluster-name> 231 namespace: <cluster-namespace> 232 ownerReferences: 233 - apiVersion: cluster.x-k8s.io/v1alpha3 234 kind: Cluster 235 name: <cluster-name> 236 uid: e3a503a8-9be1-4264-8fa2-d536532687f9 237 - apiVersion: addons.cluster.x-k8s.io/v1alpha3 238 blockOwnerDeletion: true 239 controller: true 240 kind: ClusterResourceSet 241 name: crs1 242 uid: 62c77639-92d8-46d2-ba21-a880f62f7719 243 spec: 244 bindings: 245 - clusterResourceSetName: crs1 246 resources: 247 - applied: true 248 hash: sha256:a3473f4e92ee5a2277ff37d5c559666d61d24332a497b554e65ae18e82727245 249 kind: Secret 250 lastAppliedTime: "2020-07-02T05:47:38Z" 251 name: db-secret 252 - applied: true 253 hash: sha256:c1d0dc7e51bb05945a2f99e6745dc4b1043f8a03f37ad21391fe92353a02066e 254 kind: ConfigMap 255 lastAppliedTime: "2020-07-02T05:47:39Z" 256 name: calico-addon 257 ``` 258 When a cluster is deleted, the associated `ClusterResourceBinding` will also be cleaned up. 259 When a `ClusterResourceSet` is deleted, it will be removed from the `bindings` list of all `ClusterResourceBindings` that it is listed. 260 261 `ClusterResourceSet` will use `ClusterResourceSetBinding` to decide to apply a new resource or retry to apply an old one. In `ApplyOnce` mode, if a `resource/applied` is true, 262 that resource will never be reapplied. If applying a resource is failed, `ClusterResourceSet` controller will reconcile it and use the `controller-runtime`'s exponential back-off to retry applying failed resources. 263 In case of new resource addition to a `ClusterResourceSet`, that `ClusterResourceSet` will be reconciled immediately and the new resource will be applied to all matching clusters because 264 the new resource does not exist in any `ClusterResourceBinding` lists. 265 266 #### `ApplyOnce` mode 267 268 When the same resource exist in multiple `ClusterResourceSets`, only the first one will be applied but the resource will appear as applied in all `ClusterResourceSets` in the `ClusterResourceSetsBinding/bindings`. 269 Similarly, if a resource is manually created in the workload cluster, when a `ClusterResourceSet` is applied with that resource, it will not update the existing resource to avoid any overwrites but in `ClusterResourceSetBinding`, that resource will show as applied. 270 271 #### `Reconcile` mode 272 273 ***Detecting changes*** 274 `ClusterResourceBindings` will contain consistent hash for the resource/s definitions. We will use this to detect changes, comparing the hash of the current resource/s definition with the one stored in the `ClusterResourceBindings`. 275 276 Note that this hash will change when any of the resources is updated, a resource is added or a resource is removed. This means that all resources in the same `ConfigMap` or `Secret`, and not only the one that changed, will be reapplied in any of these 3 cases. It also means that resources removed from `ConfigMap` or `Secret` won't be deleted from the target clusters. 277 278 In the next *before-after* example we can see that only one resource has changed (`ConfigMap` `calico-configmap`). However, all the 3 resources (`calico-secret1`, `calico-secret2` and `calico-configmap`) will be reapplied. 279 280 Before: 281 ```yaml 282 apiVersion: v1 283 kind: ConfigMap 284 metadata: 285 name: calico-addon 286 data: 287 calico1.yaml: |- 288 kind: Secret 289 apiVersion: v1 290 metadata: 291 name: calico-secret1 292 namespace: mysecrets 293 --- 294 kind: Secret 295 apiVersion: v1 296 metadata: 297 name: calico-secret2 298 namespace: mysecrets 299 calico2.yaml: |- 300 kind: ConfigMap 301 apiVersion: v1 302 metadata: 303 name: calico-configmap 304 namespace: myconfigmaps 305 data: 306 key: "original value" 307 ``` 308 309 After: 310 ```yaml 311 apiVersion: v1 312 kind: ConfigMap 313 metadata: 314 name: calico-addon 315 data: 316 calico1.yaml: |- 317 kind: Secret 318 apiVersion: v1 319 metadata: 320 name: calico-secret1 321 namespace: mysecrets 322 --- 323 kind: Secret 324 apiVersion: v1 325 metadata: 326 name: calico-secret2 327 namespace: mysecrets 328 calico2.yaml: |- 329 kind: ConfigMap 330 apiVersion: v1 331 metadata: 332 name: calico-configmap 333 namespace: myconfigmaps 334 data: 335 key: "value that changed" 336 ``` 337 338 ### Risks and Mitigations 339 340 #### Drift 341 342 The proposed solution only deals with changes in the resources' definitions and not with changes in the real objects in the workload clusters. If those objects are modified or deleted in the workload clusters, the `ClusterResourceSet`'s controller won't do anything and they will remain unchanged until their definition in the management cluster is updated. 343 344 This could potentially be mitigated by: 345 * Implementing a "periodic" reconciliation mode where resources are reapplied with a certain frequency even if their hash hasn't changed. 346 347 #### Deletion 348 349 Resource deletion is not supported. If a resource is removed from a `ConfigMap` or `Secret`, the hash for the CRS will change so the resources that haven't been removed will be reapplied. However, the removed resourced won't be deleted. 350 351 ## Alternatives 352 353 The Alternatives section is used to highlight and record other possible approaches to delivering the value proposed by a proposal. 354 355 ## Upgrade Strategy 356 357 This is an experimental feature supported by a new CRD and controller so there is no need to handle upgrades for existing clusters. 358 359 ## Additional Details 360 361 ### Test Plan [optional] 362 363 Extensive unit testing for all the cases supported when applying `ClusterResourceSet` resources. 364 e2e testing as part of the cluster-api e2e test suite. 365 366 ### Graduation Criteria [optional] 367 368 This proposal will follow all maturity stages (alpha, beta, GA) and then may be merged with cluster-api apis and controllers. 369 370 ## Implementation History 371 - [x] 02/20/2020: Compile a [CAEP Google Doc] following the CAEP template 372 - [x] 02/26/2020: Present proposal at a [community meeting] 373 - [x] 05/11/2020: Open proposal PR 374 375 <!-- Links --> 376 [community meeting]: https://docs.google.com/document/d/1fQNlqsDkvEggWFi51GVxOglL2P1Bvo2JhZlMhm2d-Co/edit 377 [CAEP Google Doc]: https://docs.google.com/document/d/1lWLGN66roMjXL49gKO6Dhwe7yzCnvgrCtjR9mu4rvPc/edit?ts=5eb07925# 378 [issue 2395]: https://github.com/kubernetes-sigs/cluster-api/issues/2395 379 [POC]: https://github.com/sedefsavas/cluster-api/pull/3