From a447a1a37a6f42c9569d318edda45890ad8371e7 Mon Sep 17 00:00:00 2001 From: sunshuai09 Date: Tue, 1 Nov 2022 19:47:25 +0800 Subject: [PATCH] enable mcloneset deleting pvc when pod hanging --- apis/apps/v1alpha1/cloneset_types.go | 3 + .../crd/bases/apps.kruise.io_clonesets.yaml | 4 ++ .../apps.kruise.io_uniteddeployments.yaml | 4 ++ .../cloneset/sync/cloneset_scale.go | 57 +++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/apis/apps/v1alpha1/cloneset_types.go b/apis/apps/v1alpha1/cloneset_types.go index 4d95dd224e..82aee66999 100644 --- a/apis/apps/v1alpha1/cloneset_types.go +++ b/apis/apps/v1alpha1/cloneset_types.go @@ -93,6 +93,9 @@ type CloneSetScaleStrategy struct { // The scale will fail if the number of unavailable pods were greater than this MaxUnavailable at scaling up. // MaxUnavailable works only when scaling up. MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"` + + // Enable cloneset to clean up the useless pvc when pod hangs in terminating state. + CleanUpPVC bool `json:"cleanUpPVC,omitempty"` } // CloneSetUpdateStrategy defines strategies for pods update. diff --git a/config/crd/bases/apps.kruise.io_clonesets.yaml b/config/crd/bases/apps.kruise.io_clonesets.yaml index da2fb66cdc..d713f57ecd 100644 --- a/config/crd/bases/apps.kruise.io_clonesets.yaml +++ b/config/crd/bases/apps.kruise.io_clonesets.yaml @@ -149,6 +149,10 @@ spec: description: ScaleStrategy indicates the ScaleStrategy that will be employed to create and delete Pods in the CloneSet. properties: + cleanUpPVC: + description: Enable cloneset to clean up the useless pvc when + pod hangs in terminating state. + type: boolean maxUnavailable: anyOf: - type: integer diff --git a/config/crd/bases/apps.kruise.io_uniteddeployments.yaml b/config/crd/bases/apps.kruise.io_uniteddeployments.yaml index a274937b18..ea09182526 100644 --- a/config/crd/bases/apps.kruise.io_uniteddeployments.yaml +++ b/config/crd/bases/apps.kruise.io_uniteddeployments.yaml @@ -617,6 +617,10 @@ spec: that will be employed to create and delete Pods in the CloneSet. properties: + cleanUpPVC: + description: Enable cloneset to clean up the useless + pvc when pod hangs in terminating state. + type: boolean maxUnavailable: anyOf: - type: integer diff --git a/pkg/controller/cloneset/sync/cloneset_scale.go b/pkg/controller/cloneset/sync/cloneset_scale.go index 69ca12c685..bfd2f73153 100644 --- a/pkg/controller/cloneset/sync/cloneset_scale.go +++ b/pkg/controller/cloneset/sync/cloneset_scale.go @@ -31,6 +31,7 @@ import ( "github.com/openkruise/kruise/pkg/util/expectations" "github.com/openkruise/kruise/pkg/util/lifecycle" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/klog/v2" @@ -60,6 +61,21 @@ func (r *realControl) Scale( return false, nil } + // If cloneset doesn't want to reuse pvc, clean up the existing pvc first. + // Then it looks like the pod is deleted by controller, new pod with new name + // can be created. + if updateCS.Spec.ScaleStrategy.CleanUpPVC { + ins := getInstanceIDsFromPods(pods) + usingPVCs, uselessPVCs := classifyPVCs(ins, pvcs) + if len(uselessPVCs) > 0 { + klog.V(3).Infof("Begin to clean up cloneset %s useless PVCs", controllerKey) + if modified, err := r.cleanupPVCs(updateCS, uselessPVCs); err != nil || modified { + return modified, err + } + pvcs = usingPVCs + } + } + // 1. manage pods to delete and in preDelete podsSpecifiedToDelete, podsInPreDelete, numToDelete := getPlannedDeletedPods(updateCS, pods) if modified, err := r.managePreparingDelete(updateCS, pods, podsInPreDelete, numToDelete); err != nil || modified { @@ -403,3 +419,44 @@ func (r *realControl) choosePodsToDelete(cs *appsv1alpha1.CloneSet, totalDiff in return podsToDelete } + +func (r *realControl) cleanupPVCs(cs *appsv1alpha1.CloneSet, pvcs []*v1.PersistentVolumeClaim) (bool, error) { + var modified bool + for _, pvc := range pvcs { + clonesetutils.ScaleExpectations.ExpectScale(clonesetutils.GetControllerKey(cs), expectations.Delete, pvc.Name) + if err := r.Delete(context.TODO(), pvc); err != nil { + clonesetutils.ScaleExpectations.ObserveScale(clonesetutils.GetControllerKey(cs), expectations.Delete, pvc.Name) + r.recorder.Eventf(cs, v1.EventTypeWarning, "FailedCleanUp", "failed to clean up %s: %v", pvc.Name, err) + return modified, err + } + } + return modified, nil +} + +func getInstanceIDsFromPods(pods []*v1.Pod) sets.String { + ins := sets.NewString() + for _, pod := range pods { + ins.Insert(pod.Labels[appsv1alpha1.CloneSetInstanceID]) + } + return ins +} + +func classifyPVCs(ids sets.String, pvcs []*v1.PersistentVolumeClaim) (using, useless []*v1.PersistentVolumeClaim) { + usingMap := map[types.UID]*v1.PersistentVolumeClaim{} + uselessMap := map[types.UID]*v1.PersistentVolumeClaim{} + for _, pvc := range pvcs { + if ids.Has(pvc.Labels[appsv1alpha1.CloneSetInstanceID]) { + usingMap[pvc.UID] = pvc + } else { + uselessMap[pvc.UID] = pvc + } + } + + for _, p := range usingMap { + using = append(using, p) + } + for _, p := range uselessMap { + useless = append(useless, p) + } + return using, useless +}