sigs.k8s.io/cluster-api@v1.6.3/docs/proposals/20191017-kubeadm-based-control-plane.md (about) 1 --- 2 title: Kubeadm Based Control Plane Management 3 authors: 4 - "@detiber" 5 - "@chuckha" 6 - "@randomvariable" 7 - "@dlipovetsky" 8 - "@amy" 9 reviewers: 10 - "@ncdc" 11 - "@timothysc" 12 - "@vincepri" 13 - "@akutz" 14 - "@jaypipes" 15 - "@pablochacin" 16 - "@rsmitty" 17 - "@CecileRobertMichon" 18 - "@hardikdr" 19 - "@sbueringer" 20 creation-date: 2019-10-17 21 last-updated: 2021-01-07 22 status: implementable 23 --- 24 25 # Kubeadm Based Control Plane Management 26 27 ## Table of Contents 28 29 <!-- START doctoc generated TOC please keep comment here to allow auto update --> 30 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> 31 32 - [Glossary](#glossary) 33 - [References](#references) 34 - [Summary](#summary) 35 - [Motivation](#motivation) 36 - [Goals](#goals) 37 - [Non-Goals / Future Work](#non-goals--future-work) 38 - [Proposal](#proposal) 39 - [User Stories](#user-stories) 40 - [Identified features from user stories](#identified-features-from-user-stories) 41 - [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints) 42 - [New API Types](#new-api-types) 43 - [Rollout strategy](#rollout-strategy) 44 - [Modifications required to existing API Types](#modifications-required-to-existing-api-types) 45 - [Behavioral Changes from v1alpha2](#behavioral-changes-from-v1alpha2) 46 - [Behaviors](#behaviors) 47 - [Create](#create) 48 - [Scale Up](#scale-up) 49 - [Scale Down](#scale-down) 50 - [Delete of the entire KubeadmControlPlane (kubectl delete controlplane my-controlplane)](#delete-of-the-entire-kubeadmcontrolplane-kubectl-delete-controlplane-my-controlplane) 51 - [KubeadmControlPlane rollout](#kubeadmcontrolplane-rollout) 52 - [Rolling update strategy](#rolling-update-strategy) 53 - [Constraints and Assumptions](#constraints-and-assumptions) 54 - [Remediation (using delete-and-recreate)](#remediation-using-delete-and-recreate) 55 - [Why delete and recreate](#why-delete-and-recreate) 56 - [Scenario 1: Three replicas, one machine marked for remediation](#scenario-1-three-replicas-one-machine-marked-for-remediation) 57 - [Scenario 2: Three replicas, two machines marked for remediation](#scenario-2-three-replicas-two-machines-marked-for-remediation) 58 - [Scenario 3: Three replicas, one unresponsive etcd member, one (different) unhealthy machine](#scenario-3-three-replicas-one-unresponsive-etcd-member-one-different-unhealthy-machine) 59 - [Scenario 4: Unhealthy machines combined with rollout](#scenario-4-unhealthy-machines-combined-with-rollout) 60 - [Preflight checks](#preflight-checks) 61 - [Etcd (external)](#etcd-external) 62 - [Etcd (stacked)](#etcd-stacked) 63 - [Kubernetes Control Plane](#kubernetes-control-plane) 64 - [Adoption of pre-v1alpha3 Control Plane Machines](#adoption-of-pre-v1alpha3-control-plane-machines) 65 - [Code organization](#code-organization) 66 - [Risks and Mitigations](#risks-and-mitigations) 67 - [etcd membership](#etcd-membership) 68 - [Upgrade where changes needed to KubeadmConfig are not currently possible](#upgrade-where-changes-needed-to-kubeadmconfig-are-not-currently-possible) 69 - [Design Details](#design-details) 70 - [Test Plan](#test-plan) 71 - [Graduation Criteria](#graduation-criteria) 72 - [Alpha -> Beta Graduation](#alpha---beta-graduation) 73 - [Upgrade Strategy](#upgrade-strategy) 74 - [Alternatives](#alternatives) 75 - [Implementation History](#implementation-history) 76 77 <!-- END doctoc generated TOC please keep comment here to allow auto update --> 78 79 ## Glossary 80 81 The lexicon used in this document is described in more detail [here](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/book/src/reference/glossary.md). Any discrepancies should be rectified in the main Cluster API glossary. 82 83 ### References 84 85 [Kubernetes Control Plane Management Overview](https://docs.google.com/document/d/1nlWKEr9OP3IeZO5W2cMd3A55ZXLOXcnc6dFu0K9_bms/edit#) 86 87 ## Summary 88 89 This proposal outlines a new process for Cluster API to manage control plane machines as a single concept. This includes 90 upgrading, scaling up, and modifying the underlying image (e.g. AMI) of the control plane machines. 91 92 The control plane covered by this document is defined as the Kubernetes API server, scheduler, controller manager, DNS 93 and proxy services, and the underlying etcd data store. 94 95 ## Motivation 96 97 During 2019 we saw control plane management implementations in each infrastructure provider. Much like 98 bootstrapping was identified as being reimplemented in every infrastructure provider and then extracted into Cluster API 99 Bootstrap Provider Kubeadm (CABPK), we believe we can reduce the redundancy of control plane management across providers 100 and centralize the logic in Cluster API. We also wanted to ensure that default control plane management and use of any alternative control plane management solutions are separated. 101 102 ### Goals 103 104 - To establish new resource types for control plane management 105 - To support single node and multiple node control plane instances, with the requirement that the infrastructure provider supports some type of a stable endpoint for the API Server (Load Balancer, VIP, etc). 106 - To enable scaling of the number of control plane nodes 107 - To enable declarative orchestrated control plane upgrades 108 - To provide a default machine-based implementation using kubeadm 109 - To provide a kubeadm-based implementation that is infrastructure provider agnostic 110 - To enable declarative orchestrated replacement of control plane machines, such as to roll out an OS-level CVE fix. 111 - To support Rolling Update type of rollout strategy (similar to MachineDeployment) in KubeadmControlPlane. 112 - To manage a kubeadm-based, "stacked etcd" control plane 113 - To manage a kubeadm-based, "external etcd" control plane (using a pre-existing, user-managed, etcd clusters). 114 - To manage control plane deployments across failure domains. 115 - To support user-initiated remediation: 116 E.g. user deletes a Machine. Control Plane Provider reconciles by removing the corresponding etcd member and updating related metadata 117 - To support auto remediation triggered by MachineHealthCheck objects: 118 E.g. a MachineHealthCheck marks a machine for remediation. Control Plane Provider reconciles by removing the machine and replaces it with a new one 119 **if and only if** the operation is not potentially destructive for the cluster (e.g. the operation could cause a permanent quorum loss). 120 121 ### Non-Goals / Future Work 122 123 Non-Goals listed in this document are intended to scope bound the current v1alpha3 implementation and are subject to change based on user feedback over time. 124 125 - To manage non-machine based topologies, e.g. 126 - Pod based control planes. 127 - Non-node control planes (i.e. EKS, GKE, AKS). 128 - To define a mechanism for providing a stable API endpoint for providers that do not currently have one, follow up work for this will be tracked on [this issue](https://github.com/kubernetes-sigs/cluster-api/issues/1687) 129 - To predefine the exact contract/interoperability mechanism for alternative control plane providers, follow up work for this will be tracked on [this issue](https://github.com/kubernetes-sigs/cluster-api/issues/1727) 130 - To manage CA certificates outside of what is provided by Kubeadm bootstrapping 131 - To manage etcd clusters in any topology other than stacked etcd (externally managed etcd clusters can still be leveraged). 132 - To address disaster recovery constraints, e.g. restoring a control plane from 0 replicas using a filesystem or volume snapshot copy of data persisted in etcd. 133 - To support rollbacks, as there is no data store rollback guarantee for Kubernetes. Consumers should perform backups of the cluster prior to performing potentially destructive operations. 134 - To mutate the configuration of live, running clusters (e.g. changing api-server flags), as this is the responsibility of the [component configuration working group](https://github.com/orgs/kubernetes/projects/26). 135 - To provide configuration of external cloud providers (i.e. the [cloud-controller-manager](https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/)). This is deferred to kubeadm. 136 - To provide CNI configuration. This is deferred to external, higher level tooling. 137 - To provide the upgrade logic to handle changes to infrastructure (networks, firewalls etc…) that may need to be done to support a control plane on a newer version of Kubernetes (e.g. a cloud controller manager requires updated permissions against infrastructure APIs). We expect the work on [add-on components](https://git.k8s.io/community/sig-cluster-lifecycle#cluster-addons) to help to resolve some of these issues. 138 - To provide automation around the horizontal or vertical scaling of control plane components, especially as etcd places hard performance limits beyond 3 nodes (due to latency). 139 - To support upgrades where the infrastructure does not rely on a Load Balancer for access to the API Server. 140 - To implement a fully modeled state machine and/or Conditions, a larger effort for Cluster API more broadly is being organized on [this issue](https://github.com/kubernetes-sigs/cluster-api/issues/1658) 141 142 ## Proposal 143 144 ### User Stories 145 146 1. As a cluster operator, I want my Kubernetes clusters to have multiple control plane machines to meet my SLOs with application developers. 147 2. As a developer, I want to be able to deploy the smallest possible cluster, e.g. to meet my organization’s cost requirements. 148 3. As a cluster operator, I want to be able to scale up my control plane to meet the increased demand that workloads are placing on my cluster. 149 4. As a cluster operator, I want to be able to remove a control plane replica that I have determined is faulty and should be replaced. 150 5. As a cluster operator, I want my cluster architecture to be always consistent with best practices, in order to have reliable cluster provisioning without having to understand the details of underlying data stores, replication etc… 151 6. As a cluster operator, I want to know if my cluster’s control plane is healthy in order to understand if I am meeting my SLOs with my end users. 152 7. As a cluster operator, I want to be able to quickly respond to a Kubernetes CVE by upgrading my clusters in an automated fashion. 153 8. As a cluster operator, I want to be able to quickly respond to a non-Kubernetes CVE that affects my base image or Kubernetes dependencies by upgrading my clusters in an automated fashion. 154 9. As a cluster operator, I would like to upgrade to a new minor version of Kubernetes so that my cluster remains supported. 155 10. As a cluster operator, I want to know that my cluster isn’t working properly after creation. I have ended up with an API server I can access, but kube-proxy isn’t functional or new machines are not registering themselves with the control plane. 156 11. As a cluster operator I would like to use MachineDeployment like rollout strategy to upgrade my control planes. For example in resource constrained environments I would like to my machines to be removed one-by-one before creating a new ones. I would also like to be able to rely on the default control plane upgrade mechanism without any extra effort when specific rollout strategy is not needed. 157 158 #### Identified features from user stories 159 160 1. Based on the function of kubeadm, the control plane provider must be able to scale the number of replicas of a control plane from 1 to X, meeting user stories 1 through 4. 161 2. To address user story 5, the control plane provider must provide validation of the number of replicas in a control plane. Where the stacked etcd topology is used (i.e., in the default implementation), the number of replicas must be an odd number, as per [etcd best practice](https://etcd.io/docs/v3.3.12/faq/#why-an-odd-number-of-cluster-members). When external etcd is used, any number is valid. 162 3. In service of user story 5, the kubeadm control plane provider must also manage etcd membership via kubeadm as part of scaling down (`kubeadm` takes care of adding the new etcd member when joining). 163 4. The control plane provider should provide indicators of health to meet user story 6 and 10. This should include at least the state of etcd and information about which replicas are currently healthy or not. For the default implementation, health attributes based on artifacts kubeadm installs on the cluster may also be of interest to cluster operators. 164 5. The control plane provider must be able to upgrade a control plane’s version of Kubernetes as well as updating the underlying machine image on where applicable (e.g. virtual machine based infrastructure). 165 6. To address user story 11, the control plane provider must provide Rolling Update strategy similar to MachineDeployment. With `MaxSurge` field user is able to delete old machine first during upgrade. Control plane provider should default the `RolloutStrategy` and `MaxSurge` fields such a way that scaling up is the default behavior during upgrade. 166 167 ### Implementation Details/Notes/Constraints 168 169 #### New API Types 170 171 See [kubeadm_control_plane_types.go](https://github.com/kubernetes-sigs/cluster-api/blob/release-0.3/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go) 172 173 With the following validations: 174 175 - If `KubeadmControlPlane.Spec.KubeadmConfigSpec` does not define external etcd (webhook): 176 - `KubeadmControlPlane.Spec.Replicas` is an odd number. 177 - Configuration of external etcd is determined by introspecting the provided `KubeadmConfigSpec`. 178 - `KubeadmControlPlane.Spec.Replicas` is >= 0 or is nil 179 - `KubeadmControlPlane.Spec.Version` should be a valid semantic version 180 - `KubeadmControlPlane.Spec.KubeadmConfigSpec` allows mutations required for supporting following use cases: 181 - Change of imagesRepository/imageTags (with validation of CoreDNS supported upgrade) 182 - Change of node registration options 183 - Change of pre/post kubeadm commands 184 - Change of cloud init files 185 186 And the following defaulting: 187 188 - `KubeadmControlPlane.Spec.Replicas: 1` 189 190 ##### Rollout strategy 191 192 ```go 193 type RolloutStrategyType string 194 195 const ( 196 // Replace the old control planes by new one using rolling update 197 // i.e. gradually scale up or down the old control planes and scale up or down the new one. 198 RollingUpdateStrategyType RolloutStrategyType = "RollingUpdate" 199 ) 200 ``` 201 202 - Add `KubeadmControlPlane.Spec.RolloutStrategy` defined as: 203 204 ```go 205 // The RolloutStrategy to use to replace control plane machines with 206 // new ones. 207 // +optional 208 RolloutStrategy *RolloutStrategy `json:"strategy,omitempty"` 209 ``` 210 211 - Add `KubeadmControlPlane.RolloutStrategy` struct defined as: 212 213 ```go 214 // RolloutStrategy describes how to replace existing machines 215 // with new ones. 216 type RolloutStrategy struct { 217 // Type of rollout. Currently the only supported strategy is 218 // "RollingUpdate". 219 // Default is RollingUpdate. 220 // +optional 221 Type RolloutStrategyType `json:"type,omitempty"` 222 223 // Rolling update config params. Present only if 224 // RolloutStrategyType = RollingUpdate. 225 // +optional 226 RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"` 227 } 228 ``` 229 230 - Add `KubeadmControlPlane.RollingUpdate` struct defined as: 231 232 ```go 233 // RollingUpdate is used to control the desired behavior of rolling update. 234 type RollingUpdate struct { 235 // The maximum number of control planes that can be scheduled above or under the 236 // desired number of control planes. 237 // Value can be an absolute number 1 or 0. 238 // Defaults to 1. 239 // Example: when this is set to 1, the control plane can be scaled 240 // up immediately when the rolling update starts. 241 // +optional 242 MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty"` 243 } 244 ``` 245 246 #### Modifications required to existing API Types 247 248 - Add `Cluster.Spec.ControlPlaneRef` defined as: 249 250 ```go 251 // ControlPlaneRef is an optional reference to a provider-specific resource that holds 252 // the details for provisioning the Control Plane for a Cluster. 253 // +optional 254 ControlPlaneRef *corev1.ObjectReference `json:"controlPlaneRef,omitempty"` 255 ``` 256 257 - Add `Cluster.Status.ControlPlaneReady` defined as: 258 259 ```go 260 // ControlPlaneReady defines if the control plane is ready. 261 // +optional 262 ControlPlaneReady bool `json:"controlPlaneReady,omitempty"` 263 ``` 264 265 #### Behavioral Changes from v1alpha2 266 267 - If Cluster.Spec.ControlPlaneRef is set: 268 - [Status.ControlPlaneInitialized](https://github.com/kubernetes-sigs/cluster-api/issues/1243) is set based on the value of Status.Initialized for the referenced resource. 269 - Status.ControlPlaneReady is set based on the value of Status.Ready for the referenced resource, this field is intended to eventually replace Status.ControlPlaneInitialized as a field that will be kept up to date instead of set only once. 270 - Current behavior will be preserved if `Cluster.Spec.ControlPlaneRef` is not set. 271 - CA certificate secrets that were previously generated by the Kubeadm bootstrapper will now be generated by the KubeadmControlPlane Controller, maintaining backwards compatibility with the previous behavior if the KubeadmControlPlane is not used. 272 - The kubeconfig secret that was previously created by the Cluster Controller will now be generated by the KubeadmControlPlane Controller, maintaining backwards compatibility with the previous behavior if the KubeadmControlPlane is not used. 273 274 #### Behaviors 275 276 ##### Create 277 278 - After a KubeadmControlPlane object is created, it must bootstrap a control plane with a given number of replicas. 279 - `KubeadmControlPlane.Spec.Replicas` must be an odd number. 280 - Can create an arbitrary number of control planes if etcd is external to the control plane, which will be determined by introspecting `KubeadmControlPlane.Spec.KubeadmConfigSpec`. 281 - Creating a KubeadmControlPlane with > 1 replicas is equivalent to creating a KubeadmControlPlane with 1 replica followed by scaling the KubeadmControlPlane to the desired number of replicas 282 - The kubeadm bootstrapping configuration provided via `KubeadmControlPlane.Spec.KubeadmConfigSpec` should specify the `InitConfiguration`, `ClusterConfiguration`, and `JoinConfiguration` stanzas, and the KubeadmControlPlane controller will be responsible for splitting the config and passing it to the underlying Machines created as appropriate. 283 - This is different than current usage of `KubeadmConfig` and `KubeadmConfigTemplate` where it is recommended to specify `InitConfiguration`/`ClusterConfiguration` OR `JoinConfiguration` but not both. 284 - The underlying query used to find existing Control Plane Machines is based on the following hardcoded label selector: 285 286 ```yaml 287 selector: 288 matchLabels: 289 cluster.x-k8s.io/cluster-name: my-cluster 290 cluster.x-k8s.io/control-plane: "" 291 ``` 292 293 - Generate CA certificates if they do not exist 294 - Generate the kubeconfig secret if it does not exist 295 296 Given the following `cluster.yaml` file: 297 298 ```yaml 299 kind: Cluster 300 apiVersion: cluster.x-k8s.io/v1alpha3 301 metadata: 302 name: my-cluster 303 namespace: default 304 spec: 305 clusterNetwork: 306 pods: 307 cidrBlocks: ["192.168.0.0/16"] 308 controlPlaneRef: 309 kind: KubeadmControlPlane 310 apiVersion: cluster.x-k8s.io/v1alpha3 311 name: my-controlplane 312 namespace: default 313 infrastructureRef: 314 kind: AcmeCluster 315 apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2 316 name: my-acmecluster 317 namespace: default 318 --- 319 kind: KubeadmControlPlane 320 apiVersion: cluster.x-k8s.io/v1alpha3 321 metadata: 322 name: my-control-plane 323 namespace: default 324 spec: 325 replicas: 1 326 version: v1.16.0 327 infrastructureTemplate: 328 kind: AcmeProviderMachineTemplate 329 apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2 330 namespace: default 331 name: my-acmemachinetemplate 332 kubeadmConfigSpec: 333 initConfiguration: 334 nodeRegistration: 335 name: '{{ ds.meta_data.local_hostname }}' 336 kubeletExtraArgs: 337 cloud-provider: acme 338 clusterConfiguration: 339 apiServer: 340 extraArgs: 341 cloud-provider: acme 342 controllerManager: 343 extraArgs: 344 cloud-provider: acme 345 joinConfiguration: 346 controlPlane: {} 347 nodeRegistration: 348 name: '{{ ds.meta_data.local_hostname }}' 349 kubeletExtraArgs: 350 cloud-provider: acme 351 --- 352 apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2 353 kind: AcmeProviderMachineTemplate 354 metadata: 355 name: my-acmemachinetemplate 356 namespace: default 357 spec: 358 osImage: 359 id: objectstore-123456abcdef 360 instanceType: θ9.medium 361 iamInstanceProfile: "control-plane.cluster-api-provider-acme.x-k8s.io" 362 sshKeyName: my-ssh-key 363 --- 364 apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2 365 kind: AcmeCluster 366 metadata: 367 name: my-acmecluster 368 namespace: default 369 spec: 370 region: antarctica-1 371 ``` 372 373  374  375  376  377 378 ##### Scale Up 379 380 - Allow scale up a control plane with stacked etcd to only odd numbers, as per 381 [etcd best practice](https://etcd.io/docs/v3.3.12/faq/#why-an-odd-number-of-cluster-members). 382 - However, allow a control plane using an external etcd cluster to scale up to other numbers such as 2 or 4. 383 - Scale up operations must not be done in conjunction with: 384 - Adopting machines 385 - Upgrading machines 386 - Scale up operations are blocked based on Etcd and control plane preflight checks. 387 - See [Preflight checks](#preflight-checks) below. 388 - Scale up operations creates the next machine in the failure domain with the fewest number of machines. 389 390  391 392 ##### Scale Down 393 394 - Allow scale down a control plane with stacked etcd to only odd numbers, as per 395 [etcd best practice](https://etcd.io/docs/v3.3.12/faq/#why-an-odd-number-of-cluster-members). 396 - However, allow a control plane using an external etcd cluster to scale down to other numbers such as 2 or 4. 397 - Scale down operations must not be done in conjunction with: 398 - Adopting machines 399 - Upgrading machines 400 - Scale down operations are blocked based on Etcd and control plane preflight checks. 401 - See [Preflight checks](#preflight-checks) below. 402 - Scale down operations removes the oldest machine in the failure domain that has the most control-plane machines on it. 403 - Allow scaling down of KCP with the possibility of marking specific control plane machine(s) to be deleted with delete annotation key. The presence of the annotation will affect the rollout strategy in a way that, it implements the following prioritization logic in descending order, while selecting machines for scale down: 404 - outdatedMachines with the delete annotation 405 - machines with the delete annotation 406 - outdated machines 407 - all machines 408 409  410 411 ##### Delete of the entire KubeadmControlPlane (kubectl delete controlplane my-controlplane) 412 413 - KubeadmControlPlane deletion should be blocked until all the worker nodes are deleted. 414 - Completely removing the control plane and issuing a delete on the underlying machines. 415 - User documentation should focus on deletion of the Cluster resource rather than the KubeadmControlPlane resource. 416 417 ##### KubeadmControlPlane rollout 418 419 KubeadmControlPlane rollout operations rely on [scale up](#scale up) and [scale down](#scale_down) which are be blocked based on Etcd and control plane preflight checks. 420 - See [Preflight checks](#preflight-checks) below. 421 422 KubeadmControlPlane rollout is triggered by: 423 424 - Changes to Version 425 - Changes to the kubeadmConfigSpec 426 - Changes to the infrastructureRef 427 - The `rolloutAfter` field, which can be set to a specific time in the future 428 - Set to `nil` or the zero value of `time.Time` if no upgrades are desired 429 - An upgrade will run after that timestamp is passed 430 - Good for scheduling upgrades/SLOs 431 - Set `rolloutAfter` to now (in RFC3339 form) if an upgrade is required immediately 432 433 - The controller should tolerate the manual or automatic removal of a replica during the upgrade process. A replica that fails during the upgrade may block the completion of the upgrade. Removal or other remedial action may be necessary to allow the upgrade to complete. 434 435 - In order to determine if a Machine to be rolled out, KCP implements the following: 436 - The infrastructureRef link used by each machine at creation time is stored in annotations at machine level. 437 - The kubeadmConfigSpec used by each machine at creation time is stored in annotations at machine level. 438 - If the annotation is not present (machine is either old or adopted), we won't roll out on any possible changes made in KCP's ClusterConfiguration given that we don't have enough information to make a decision. Users should use KCP.Spec.RolloutAfter field to force a rollout in this case. 439 440 ##### Rolling update strategy 441 442 Currently KubeadmControlPlane supports only one rollout strategy type the `RollingUpdateStrategyType`. Rolling upgrade strategy's behavior can be modified by using `MaxSurge` field. The field values can be an absolute number 0 or 1. 443 444 When `MaxSurge` is set to 1 the rollout algorithm is as follows: 445 446 - Find Machines that have an outdated spec 447 - If there is a machine requiring rollout 448 - Scale up control plane creating a machine with the new spec 449 - Scale down control plane by removing one of the machine that needs rollout (the oldest out-of date machine in the failure domain that has the most control-plane machines on it) 450 451 When `MaxSurge` is set to 0 the rollout algorithm is as follows: 452 453 - KubeadmControlPlane verifies that control plane replica count is >= 3 454 - Find Machines that have an outdated spec and scale down the control plane by removing the oldest out-of-date machine. 455 - Scale up control plane by creating a new machine with the updated spec 456 457 > NOTE: Setting `MaxSurge` to 0 could be use in resource constrained environment like bare-metal, OpenStack or vSphere resource pools, etc when there is no capacity to Scale up the control plane. 458 459 ###### Constraints and Assumptions 460 461 * A stable endpoint (provided by DNS or IP) for the API server will be required in order 462 to allow for machines to maintain a connection to control plane machines as they are swapped out 463 during upgrades. This proposal is agnostic to how this is achieved, and is being tracked 464 in https://github.com/kubernetes-sigs/cluster-api/issues/1687. The control plane controller will use 465 the presence of the apiEndpoints status field of the cluster object to determine whether or not to proceed. 466 This behaviour is currently implicit in the implementations for cloud providers that provider a load balancer construct. 467 468 * Infrastructure templates are expected to be immutable, so infrastructure template contents do not have to be hashed in order to detect 469 changes. 470 471 ##### Remediation (using delete-and-recreate) 472 473 - KCP remediation is triggered by the MachineHealthCheck controller marking a machine for remediation. See 474 [machine-health-checking proposal](https://github.com/kubernetes-sigs/cluster-api/blob/11485f4f817766c444840d8ea7e4e7d1a6b94cc9/docs/proposals/20191030-machine-health-checking.md) 475 for additional details. When there are multiple machines that are marked for remediation, the oldest one will be remediated first. 476 477 - Following rules should be satisfied in order to start remediation 478 - One of the following apply: 479 - The cluster MUST not be initialized yet (the failure happens before KCP reaches the initialized state) 480 - The cluster MUST have at least two control plane machines, because this is the smallest cluster size that can be remediated. 481 - Previous remediation (delete and re-create) MUST have been completed. This rule prevents KCP to remediate more machines while the 482 replacement for the previous machine is not yet created. 483 - The cluster MUST have no machines with a deletion timestamp. This rule prevents KCP taking actions while the cluster is in a transitional state. 484 - Remediation MUST preserve etcd quorum. This rule ensures that we will not remove a member that would result in etcd 485 losing a majority of members and thus become unable to field new requests (note: this rule applies only to CP already 486 initialized and with managed etcd) 487 488 - Additionally following opt-in safeguards will be put in place: 489 - If we are remediating the same machine (delete, re-create, replacement machine gets unhealthy), it will be possible 490 to define a maximum number of retries, thus preventing unnecessary load on infrastructure provider e.g. in case of quota problems. 491 - If we are remediating the same machine (delete, re-create, replacement machine gets unhealthy), it will be possible 492 to define a delay between each retry, thus allowing the infrastructure provider to stabilize in case of temporary problems. 493 494 - When all the conditions for starting remediation are satisfied, KCP temporarily suspend any operation in progress 495 in order to perform remediation. 496 - Remediation will be performed by issuing a delete on the unhealthy machine; after deleting the machine, KCP 497 will restore the target number of machines by triggering a scale up (current replicas<desired replicas) and then 498 eventually resume the rollout action. 499 See [why delete and recreate](#why-delete-and-recreate) for an explanation about why KCP should remove the member first and then add its replacement. 500 501 ###### Why delete and recreate 502 503 When replacing a KCP machine the most critical component to be taken into account is etcd, and 504 according to the [etcd documentation](https://etcd.io/docs/v3.5/faq/#should-i-add-a-member-before-removing-an-unhealthy-member), 505 it's important to remove an unhealthy etcd member first and then add its replacement: 506 507 - etcd employs distributed consensus based on a quorum model; (n/2)+1 members, a majority, must agree on a proposal before 508 it can be committed to the cluster. These proposals include key-value updates and membership changes. This model totally 509 avoids potential split brain inconsistencies. The downside is permanent quorum loss is catastrophic. 510 511 - How this applies to membership: If a 3-member cluster has 1 downed member, it can still make forward progress because 512 the quorum is 2 and 2 members are still live. However, adding a new member to a 3-member cluster will increase the quorum 513 to 3 because 3 votes are required for a majority of 4 members. Since the quorum increased, this extra member buys nothing 514 in terms of fault tolerance; the cluster is still one node failure away from being unrecoverable. 515 516 - Additionally, adding new members to an unhealthy control plane might be risky because it may turn out to be misconfigured 517 or incapable of joining the cluster. In that case, there's no way to recover quorum because the cluster has two members 518 down and two members up, but needs three votes to change membership to undo the botched membership addition. etcd will 519 by default reject member add attempts that could take down the cluster in this manner. 520 521 - On the other hand, if the downed member is removed from cluster membership first, the number of members becomes 2 and 522 the quorum remains at 2. Following that removal by adding a new member will also keep the quorum steady at 2. So, even 523 if the new node can't be brought up, it's still possible to remove the new member through quorum on the remaining live members. 524 525 As a consequence KCP remediation should remove unhealthy machine first and then add its replacement. 526 527 Additionally, in order to make this approach more robust, KCP will test each etcd member for responsiveness before 528 using the Status endpoint and determine as best as possible that we would not exceed failure tolerance by removing a machine. 529 This should ensure we are not taking actions in case there are other etcd members not properly working on machines 530 not (yet) marked for remediation by the MachineHealthCheck. 531 532 ###### Scenario 1: Three replicas, one machine marked for remediation 533 534 If MachineHealthCheck marks one machine for remediation in a control-plane with three replicas, we will look at the etcd 535 status of each machine to determine if we have at most one failed member. Assuming the etcd cluster is still all healthy, 536 or the only unresponsive member is the one to be remediated, we will scale down the machine that failed the MHC and 537 then scale up a new machine to replace it. 538 539 ###### Scenario 2: Three replicas, two machines marked for remediation 540 541 If MachineHealthCheck marks two machines for remediation in a control-plane with three replicas, remediation might happen 542 depending on the status of the etcd members on the three replicas. 543 544 As long as we continue to only have at most one unhealthy etcd member, we will scale down an unhealthy machine, 545 wait for it to provision and join the cluster, and then scale down the other machine. 546 547 However, if more than one etcd member is unhealthy, remediation would not happen and manual intervention would be required 548 to fix the unhealthy machine. 549 550 ###### Scenario 3: Three replicas, one unresponsive etcd member, one (different) unhealthy machine 551 552 It is possible to have a scenario where a different machine than the one that failed the MHC has an unresponsive etcd. 553 In this scenario, remediation would not happen and manual intervention would be required to fix the unhealthy machine. 554 555 ###### Scenario 4: Unhealthy machines combined with rollout 556 557 When there exist unhealthy machines and there also have been configuration changes that trigger a rollout of new machines to occur, 558 remediation and rollout will occur in tandem. 559 560 This is to say that unhealthy machines will first be scaled down, and replaced with new machines that match the desired new spec. 561 Once the unhealthy machines have been replaced, the remaining healthy machines will also be replaced one-by-one as well to complete the rollout operation. 562 563 ##### Preflight checks 564 565 This paragraph describes KCP preflight checks specifically designed to ensure a kubeadm 566 generated control-plane is stable before proceeding with KCP actions like scale up, scale down and rollout. 567 568 Preflight checks status is accessible via conditions on the KCP object and/or on the controlled machines. 569 570 ###### Etcd (external) 571 572 Etcd connectivity is the only metric used to assert etcd cluster health. 573 574 ###### Etcd (stacked) 575 576 Etcd is considered healthy if: 577 578 - There are an equal number of control plane Machines and members in the etcd cluster. 579 - This ensures there are no members that are unaccounted for. 580 - Each member reports the same list of members. 581 - This ensures that there is only one etcd cluster. 582 - Each member does not have any active alarms. 583 - This ensures there is nothing wrong with the individual member. 584 585 The KubeadmControlPlane controller uses port-forwarding to get to a specific etcd member. 586 587 ###### Kubernetes Control Plane 588 589 - There are an equal number of control plane Machines and api server pods checked. 590 - This ensures that Cluster API is tracking all control plane machines. 591 - Each control plane node has an api server pod that has the Ready condition. 592 - This ensures that the API server can contact etcd and is ready to accept requests. 593 - Each control plane node has a controller manager and a scheduler pod that has the Ready condition. 594 - This ensures the control plane can manage default Kubernetes resources. 595 596 ##### Adoption of pre-v1alpha3 Control Plane Machines 597 598 - Existing control plane Machines will need to be updated with labels matching the expected label selector. 599 - The KubeadmConfigSpec can be re-created from the referenced KubeadmConfigs for the Machines matching the label selector. 600 - If there is not an existing initConfiguration/clusterConfiguration only the joinConfiguration will be populated. 601 - In v1alpha2, the Cluster API Bootstrap Provider is responsible for generating certificates based upon the first machine to join a cluster. The OwnerRef for these certificates are set to that of the initial machine, which causes an issue if that machine is later deleted. For v1alpha3, control plane certificate generation will be replicated in the KubeadmControlPlane provider. Given that for v1alpha2 these certificates are generated with deterministic names, i.e. prefixed with the cluster name, the migration mechanism should replace the owner reference of these certificates during migration. The bootstrap provider will need to be updated to only fallback to the v1alpha2 secret generation behavior if Cluster.Spec.ControlPlaneRef is nil. 602 - In v1alpha2, the Cluster API Bootstrap Provider is responsible for generating the kubeconfig secret; during adoption the adoption of this secret is set to the KubeadmConfig object. 603 - To ease the adoption of v1alpha3, the migration mechanism should be built into Cluster API controllers. 604 605 #### Code organization 606 607 The types introduced in this proposal will live in the `cluster.x-k8s.io` API group. The controller(s) will also live inside `sigs.k8s.io/cluster-api`. 608 609 ### Risks and Mitigations 610 611 #### etcd membership 612 613 - If the leader is selected for deletion during a replacement for upgrade or scale down, the etcd cluster will be unavailable during that period as leader election takes place. Small time periods of unavailability should not significantly impact the running of the managed cluster’s API server. 614 - Replication of the etcd log, if done for a sufficiently large data store and saturates the network, machines may fail leader election, bringing down the cluster. To mitigate this, the control plane provider will only create machines serially, ensuring cluster health before moving onto operations for the next machine. 615 - When performing a scaling operation, or an upgrade using create-swap-delete, there are periods when there are an even number of nodes. Any network partitions or host failures that occur at this point will cause the etcd cluster to split brain. Etcd 3.4 is under consideration for Kubernetes 1.17, which brings non-voting cluster members, which can be used to safely add new machines without affecting quorum. [Changes to kubeadm](https://github.com/kubernetes/kubeadm/issues/1793) will be required to support this and is out of scope for the time frame of v1alpha3. 616 617 #### Upgrade where changes needed to KubeadmConfig are not currently possible 618 619 - We don't anticipate that this will immediately cause issues, but could potentially cause problems when adopt new versions of the Kubeadm configuration that include features such as kustomize templates. These potentially would need to be modified as part of an upgrade. 620 621 ## Design Details 622 623 ### Test Plan 624 625 Standard unit/integration & e2e behavioral test plans will apply. 626 627 ### Graduation Criteria 628 629 #### Alpha -> Beta Graduation 630 631 This work is too early to detail requirements for graduation to beta. At a minimum, etcd membership and quorum risks will need to be addressed prior to beta. 632 633 ### Upgrade Strategy 634 635 - v1alpha2 managed clusters that match certain known criteria should be able to be adopted as part of the upgrade to v1alpha3, other clusters should continue to function as they did previously. 636 637 ## Alternatives 638 639 For the purposes of designing upgrades, two existing lifecycle managers were examined in detail: kOps and Cloud Foundry Container Runtime. Their approaches are detailed in the accompanying "[Cluster API Upgrade Experience Reports](https://docs.google.com/document/d/1RnUG9mHrS_qmhmm052bO6Wu0dldCamwPmTA1D0jCWW8/edit#)" document. 640 641 ## Implementation History 642 643 - [x] 10/17/2019: Initial Creation 644 - [x] 11/19/2019: Initial KubeadmControlPlane types added [#1765](https://github.com/kubernetes-sigs/cluster-api/pull/1765) 645 - [x] 12/04/2019: Updated References to ErrorMessage/ErrorReason to FailureMessage/FailureReason 646 - [x] 12/04/2019: Initial stubbed KubeadmControlPlane controller added [#1826](https://github.com/kubernetes-sigs/cluster-api/pull/1826) 647 - [x] 07/09/2020: Document updated to reflect changes up to v0.3.9 release 648 - [x] 22/09/2020: KCP remediation added 649 - [x] 10/05/2021: Support for remediation of failures while upgrading 1 node CP 650 - [x] 05/01/2022: Support for remediation while provisioning the CP (both first CP and CP machines while current replica < desired replica); Allow control of remediation retry behavior.