sigs.k8s.io/cluster-api-provider-aws@v1.5.5/docs/proposal/20220712-garbage-collection.md (about) 1 --- 2 title: External Resource Garbage Collection 3 authors: 4 - "@richardcase" 5 - "@andrewmyhre" 6 reviewers: 7 - "@sedefsavas" 8 - "@dlipovetsky" 9 creation-date: 2022-07-12 10 last-updated: 2022-07-20 11 status: implemented 12 see-also: 13 - https://github.com/kubernetes-sigs/cluster-api-provider-aws/issues/1718 14 - https://github.com/kubernetes-sigs/cluster-api-provider-aws/pull/3518 15 replaces: [] 16 superseded-by: [] 17 --- 18 19 # External Resource Garbage Collection 20 21 ## Table of Contents 22 23 - [External Resource Garbage Collection](#external-resource-garbage-collection) 24 - [Table of Contents](#table-of-contents) 25 - [Glossary](#glossary) 26 - [Summary](#summary) 27 - [Motivation](#motivation) 28 - [Goals](#goals) 29 - [Non-Goals/Future Work](#non-goalsfuture-work) 30 - [Proposal](#proposal) 31 - [User Stories](#user-stories) 32 - [Story 1](#story-1) 33 - [Story 2](#story-2) 34 - [Story 3](#story-3) 35 - [Story 4](#story-4) 36 - [Requirements](#requirements) 37 - [Functional](#functional) 38 - [Non-Functional](#non-functional) 39 - [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints) 40 - [Proposed Changes](#proposed-changes) 41 - [API Changes](#api-changes) 42 - [Controller Changes](#controller-changes) 43 - [New Garbage Collection Service](#new-garbage-collection-service) 44 - [clusterawsadm changes](#clusterawsadm-changes) 45 - [Alternative Approaches Considered](#alternative-approaches-considered) 46 - [Using CCM to do the delete](#using-ccm-to-do-the-delete) 47 - [Risks and Mitigations](#risks-and-mitigations) 48 - [Replicating CCM](#replicating-ccm) 49 - [Similar functionality in upstream CAPI](#similar-functionality-in-upstream-capi) 50 - [Upgrade Strategy](#upgrade-strategy) 51 - [Additional Details](#additional-details) 52 - [Test Plan](#test-plan) 53 - [Graduation Criteria](#graduation-criteria) 54 - [Alpha](#alpha) 55 - [Beta](#beta) 56 - [Stable](#stable) 57 - [Implementation History](#implementation-history) 58 59 ## Glossary 60 61 - CAPA - An abbreviation of Cluster API Provider AWS. 62 - ELB - Elastic Load Balancer 63 - NLB - Network Load Balancer 64 - CCM - Cloud Controller Manager 65 66 ## Summary 67 68 If you create a workload cluster using CAPA which then in turn creates a `Service` of type `LoadBalancer` this results in a load balancer being created in AWS for that service. The type of load balancer created by default is a **Classic ELB** but you can also create a NLB by annotating your service. For example: 69 70 ```yaml 71 apiVersion: v1 72 kind: Service 73 metadata: 74 name: podinfo-nlb 75 annotations: 76 service.beta.kubernetes.io/aws-load-balancer-type: "nlb" 77 ``` 78 79 If you try to delete the workload cluster using CAPI/CAPA then it will fail to delete the clusters infrastructure fully in AWS as the VPC is still being used by the NLB that was created. For example: 80 81 ```text 82 E0609 15:49:16.022022 ###### API Changes) b │ 83 │ efore detaching the gateway.\n\tstatus code: 400, request id: 65dc0fa0-584f-4256-baf5-a2aac2d2dde4" "reconciler group"="controlplane.cluster.x-k8s.io" "reconciler kind"="AWSManaged │ 84 │ ControlPlane" "name"="capi-managed-test-control-plane" "namespace"="default" 85 ``` 86 87 Currently, CAPA will attempt to delete all the resources it has directly created as part of the cluster lifecycle management. However, if the CCM in the workload cluster has created any resources then these will not be attempted to be deleted. 88 89 This proposal outlines a new feature that will be added to CAPA that will delete externally created resources, such as load balancers & security groups, of the workload cluster. This will be referred to as **garbage collection**. 90 91 The new feature is expected to be compatible with unmanaged (i.e. EC2 control plane) and EKS CAPA created clusters. 92 93 ## Motivation 94 95 Adopters of CAPA expect that a request to delete a cluster should succeed and preferably that there be no external AWS resources for that cluster orphaned. 96 97 The traditional thinking is that a user should delete all the workloads on the cluster before deleting the actual cluster. But the reality is that some clusters are short-lived (testing & dev clusters are a good example) and these are normally deleted via `kubectl delete Cluster mytest` without deleting the resources from the cluster first. 98 99 This proposal aims to make this a better experience for the users of CAPA. 100 101 ### Goals 102 103 1. To delete AWS resources that were created by CCM in the workload cluster. 104 2. To work across unmanaged (i.e. EC2 control plane) and managed (i.e. EKS) clusters. 105 3. Solution must work in a scenario where GitOps is used. 106 107 ### Non-Goals/Future Work 108 109 - Delete EBS volumes created by the CCM 110 - This will be considered as part of future work 111 - Clean up other resources created by something other than the CCM (for example a custom operator) 112 - Fine grained control of which clusters will be garbage collected or not 113 - Initially if the feature is enabled it will be an opt-out model 114 - We will add fine-grained control in a future enhancement 115 116 ## Proposal 117 118 ### User Stories 119 120 #### Story 1 121 122 As a platform operator/engineer 123 I want to delete a cluster and all its associated AWS resources 124 When not using GitOps 125 So that there are no orphaned/unused AWS resources 126 127 #### Story 2 128 129 As a platform operator/engineer 130 I want to be able to delete a cluster and all its associated AWS resources 131 When using a GitOps tools (like Flux/Argo) 132 So that there are no orphaned/unused AWS resources 133 134 #### Story 3 135 136 As a platform operator/engineer 137 I want to be able to opt-out a cluster of being garbage collected 138 139 #### Story 4 140 141 As a platform operator/engineer 142 I want to be able to opt-in/opt-out a cluster for garbage collection 143 After it has been created 144 So that i can investigate/overcome issues 145 146 ## Requirements 147 148 ### Functional 149 150 <a name="FR1">FR1.</a> CAPA MUST support cleaning up of AWS resources created by the CCM for a tenant cluster when not using GitOps. 151 152 <a name="FR2">FR2.</a> CAPA MUST support cleaning up of AWS resources created by the CCM for a tenant cluster when using GitOps. 153 154 <a name="FR3">FR3.</a> CAPA MUST support cleaning up of AWS resources for unmanaged and managed clusters 155 156 <a name="FR4">FR4.</a> CAPA MUST support a way to opt-out of garbage collection at any point before cluster deletion. 157 158 <a name="FR5">FR5.</a> CAPI MUST not allow me to delete a cluster fully until garbage collection has occurred. 159 160 <a name="FR6">FR6.</a> CAPA SHOULD provide a way for me to opt-in or opt-out a cluster from garbage collection AFTER it has been created. 161 162 ### Non-Functional 163 164 <a name="NFR8">NFR8.</a> CAPA MUST be able to easily add additional AWS resource clean up in the future. 165 166 <a name="NFR9">NFR9.</a> Unit tests MUST exist for new garbage collection code. 167 168 <a name="NFR10">NFR10.</a> e2e tests MUST exist for the new garbage collection code for both unmanaged and managed clusters. 169 170 ### Implementation Details/Notes/Constraints 171 172 #### Proposed Changes 173 174 In the initial implementation of garbage collection, if the feature is enabled, all clusters will be garbage collected by default. However, we will supply a means to opt-out at any time prior to cluster deletion as per [FR4](#FR4). 175 176 > NOTE: garbage collection will be experimental initially and will be enabled via a feature flag. 177 178 Garbage collection occurs during the reconciliation for the deletion of a workload cluster. The following sequence diagram depicts what will happen when you delete a workload cluster with CAPI/CAPA with this change. The numbers will be referenced in the following descriptions. 179 180  181 182 ##### API Changes 183 184 If the garbage collection feature has been enabled via the feature flag then a user can mark a cluster as opting out of garbage collection ([FR4](#FR4)) when they apply the yaml to the cluster or at any time prior to deletion. This will be accomplished by annotating the **AWSCluster** or **AWSManagedControlPlane** with the `aws.cluster.x-k8s.io/external-resource-gc` annotation and setting its value to **false**. 185 186 If the `aws.cluster.x-k8s.io/external-resource-gc` annotation is absent or its value is set to **true** then the CAPA created cluster will be garbage collected. 187 188 This annotation name will be in a publicly exported package. 189 190 ##### Controller Changes 191 192 The controllers for `AWSCluster` and `AWSManagedControlPlane` will be modified so that on the creation of the controllers you can indicate that the garbage collection feature flag is enabled. In [main.go](../../main.go) we will look to see if the feature flag is enabled and pass this in when creating the controllers. 193 194 The **reconcileDelete** of the controllers for `AWSCluster` and `AWSManagedControlPlane` will be modified so that garbage collection is performed when a the infra cluster is deleted. Garbage Collection will be encapsulated in a new service (gc_service). 195 196 The point at which we do the garbage collection is important. If we do it too soon we run the risk of the resources being re-created in AWS. The **reconcileDelete** will have 3 distinct phases: 197 198 - Delete CAPA owned AWS resources for the workload cluster that are not related to the **NetworkSpec**. This will be done via the existing services in CAPA (5, 6). 199 - If the gc feature is enabled then **ReconcileDelete** will be called (7) on the new garbage collection service. Its the role of the garbage collection service to determine if GC should be done, identify the CCM created AWS resources for the cluster and delete them (8). 200 - Delete CAPA owned AWS resources for the workload cluster that are related to the **NetworkSpec**. This will be done via the existing network service (9,10). 201 202 ##### New Garbage Collection Service 203 204 For cluster deletion there will be a **ReconcileDelete** function. The first task of this function is to determine if the workload cluster's AWS resources should be garbage collected. The AWS resources will be garbage collected if either of these are true: 205 206 - the `aws.cluster.x-k8s.io/external-resource-gc` annotation is absent 207 - the `aws.cluster.x-k8s.io/external-resource-gc` annotation exists and its value is set to **true** 208 209 If the AWS resources are to be garbage collected the next task of **ReconcileDelete** is to identify the AWS resources that have been created for the workload cluster via its CCM. And then for the identified resources delete them in AWS. 210 211 To identify the resources that the CCM has created for the cluster we will use the **AWS Resource Tagging API** to query for all resources that have a label called `kubernetes.io/cluster/[CLUSTERNAME]` with a value of `owned`. Note `[CLUSTERNAME]` will be replaced with the Kubernetes cluster name. 212 213 Based on the list of resources returned we will group these by the owing AWS service (i.e. **ec2**, **elasticloadbalancing**). The grouped resources will then be passed to a function for that service which will take care of cleaning up the resources in AWS via API calls (8). 214 215 The reason we are grouping by AWS service is that order can matter when deleting. For example, with the **elasticloadbalancing** service you need to delete the load balancers before any target groups. 216 217 We will need to create the gc service so that it's easy to add new clean up functions for services in the future [NFR8](#NFR8). 218 219 The **ReconcileDelete** implementation is idempotent. This is important because the controller could crash at any point and the delete reconciliation would restart from the beginning again. This means our clean up functions could be called multiple times. 220 221 > NOTE: we will initally not handle clean-up of EBS volumes due to the potential risk of accidental data deletion. This will be considered for a future enhancement. 222 223 ##### clusterawsadm changes 224 225 We would like to supply a way for the user to manually mark a cluster as requiring garbage collection and vice versa opting out of garbage collection [FR6](#FR6). 226 227 We will add 2 new commands to `clusterawsadm` to perform this: 228 229 - **clusterawsadm gc enable** - this will add the `aws.cluster.x-k8s.io/external-resource-gc` annotation to the infra cluster object and set its value to `true`. 230 - **clusterawsadm gc disable** - this will add the `aws.cluster.x-k8s.io/external-resource-gc` annotation to the infra cluster object and sets its value `false`. 231 232 ### Alternative Approaches Considered 233 234 #### Using CCM to do the delete 235 236 The initial implementation of the garbage collector relied on the CCM in the workload cluster doing the delete. When a cluster is deleted CAPA would pause the delete reconciliation until garbage collection has been done. 237 238 The garbage collector (a separate controller) would: 239 240 - Connect to the tenant cluster and get a list of `Services` of type `LoadBalancer`. 241 - Delete each of the `Services` of type `LoadBalancer`. At this point, the CCM in the workload cluster at this point will delete the resources it created in AWS. 242 - Requeue until all the services as deleted. 243 - Once all the `Services` have been deleted in the workload cluster then we would mark the CAPA infra cluster to indicate that it had been garbage collection. This would probably be done via adding an annotation. 244 245 After the cluster has been marked as garbage collected the normal delete reconciliation has be unpaused and start. 246 247 **Benefits** 248 249 - We don't have to write out own deletion code as we rely on the CCM. 250 251 **Downsides** 252 253 - With GitOps this is problematic. The garbage collector may delete a service but the tha GitOps operator could reapply the Service and the resources will get re-created. This would potentially surface as a weird timing bug. 254 - We need to add code to all controllers to pause delete until gc has been done 255 256 ### Risks and Mitigations 257 258 #### Replicating CCM 259 260 As we are not relying on the CCM to do the deletion it means that we run the risk of replicating large parts of the CCM. To mitigate this we will only focus on cleaning up resources that can potentially block the CAPA deletion process. 261 262 #### Similar functionality in upstream CAPI 263 264 There is the possibility that similar and more generalised functionality will be added to upstream CAPI. If this happens and it meets our needs then we will refactor this code to work with the new mechanism and if required deprecate this feature. To mitigate the impact we should keep this feature as experimental for longer than we would do normally as this gives us the ability to deprecate it quickly. 265 266 ## Upgrade Strategy 267 268 There are no API changes. However, we have introduced a new feature that will need to be enabled. For existing management clusters you will have to enable the `ExternalResourceGC` feature. This can be done when via editing the `Deployment` for CAPA or at the time of `clusterctl init`. 269 270 If you enabled the feature for an existing CAPI management cluster the existing clusters will not be marked as requiring garbage collection. If you wanted to enabled garbage collection for those existing clusters then you can use the the new `clusterawsadm gc enable` command, or add annotations using any API client. 271 272 ## Additional Details 273 274 ### Test Plan 275 276 - Unit tests to validate the functionality of the new garbage collection service 277 - Unit tests to validate the functionality of the new **clusterawsadm** commands. 278 - e2e tests to test clean-up for un-managed and managed clusters 279 280 ### Graduation Criteria 281 282 #### Alpha 283 284 - Initial version as defined by this proposal 285 286 #### Beta 287 288 - At least 1 year in alpha 289 - More control over which clusters will be garbage collected (i.e. via label selectors) 290 - Ability to enable/disable which resources will be clean-up (i.e. optionally include EBS volumes) 291 - Full e2e coverage. 292 293 #### Stable 294 295 - At least 6 months in beta 296 - No alternative CAPI solution in active development 297 298 ## Implementation History 299 300 - [x] 2022/07/11: Change discussed CAPA office hours 301 - [x] 2022/07/12: Initial proposal 302 - [ ] 2022/07/20: Open proposal PR 303 304 <!-- Links -->