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