Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable cloneset deleting pvc when pod hanging #1113

Merged
merged 1 commit into from
Jan 3, 2023

Conversation

willise
Copy link
Contributor

@willise willise commented Nov 1, 2022

Ⅰ. Describe what this PR does

fixes #1099

Ⅱ. Does this pull request fix one issue?

fixes #1099

Ⅲ. Describe how to verify it

  1. Create a cloneset with setting "cleanUpPVC=false" and PVC
  2. Edit a pod created by cloneset with a finalizer
  3. Delete the above pod and verify the new pod can't be created with name conflict
  4. Edit cloneset with setting "cleanUpPVC=true"
  5. Verify a new pod with new PVC has been created and old pod hangs in terminating state.

Ⅳ. Special notes for reviews

@kruise-bot
Copy link

Welcome @willise! It looks like this is your first PR to openkruise/kruise 🎉

@kruise-bot kruise-bot added the size/M size/M: 30-99 label Nov 1, 2022
@codecov-commenter
Copy link

codecov-commenter commented Nov 1, 2022

Codecov Report

Merging #1113 (ec8d173) into master (53fb7e1) will decrease coverage by 0.39%.
The diff coverage is 18.91%.

@@            Coverage Diff             @@
##           master    #1113      +/-   ##
==========================================
- Coverage   49.73%   49.33%   -0.40%     
==========================================
  Files         137      138       +1     
  Lines       19331    19589     +258     
==========================================
+ Hits         9614     9664      +50     
- Misses       8667     8868     +201     
- Partials     1050     1057       +7     
Flag Coverage Δ
unittests 49.33% <18.91%> (-0.40%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
pkg/control/pubcontrol/pub_control.go 25.23% <0.00%> (-0.98%) ⬇️
pkg/control/pubcontrol/pub_control_utils.go 50.99% <0.00%> (-1.04%) ⬇️
pkg/controller/cloneset/sync/cloneset_scale.go 28.25% <ø> (ø)
pkg/controller/cloneset/utils/cloneset_utils.go 0.00% <0.00%> (ø)
...tentpodstate/persistent_pod_state_event_handler.go 0.00% <0.00%> (ø)
...availablebudget/podunavailablebudget_controller.go 38.03% <0.00%> (-1.19%) ⬇️
...ller/podunavailablebudget/pub_pod_event_handler.go 26.78% <0.00%> (+0.31%) ⬆️
...g/webhook/pod/validating/pod_unavailable_budget.go 68.83% <ø> (+5.73%) ⬆️
pkg/controller/cloneset/cloneset_controller.go 44.95% <11.53%> (-7.99%) ⬇️
...sistentpodstate/persistent_pod_state_controller.go 31.18% <18.18%> (-1.68%) ⬇️
... and 9 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@veophi
Copy link
Member

veophi commented Nov 2, 2022

How about taking the PVCs related with Competed Pods(Phase=Failed || Phase=Succeeded)?

@zmberg
Copy link
Member

zmberg commented Nov 2, 2022

@willise If the Pod is in the Terminating, it is still risky to delete the PVC directly. The difficulty with this way is that we can't quite tell if it's a normal process or a Hang. I agree with @FillZpp 's idea of adding AlwaysCreatePVC in spec.scaleStrategy to decide whether it should reuse the instanceId of existing free PVCs when creating new Pod.

@willise
Copy link
Contributor Author

willise commented Nov 2, 2022

How about taking the PVCs related with Competed Pods(Phase=Failed || Phase=Succeeded)?

Thank you for your reply. I am not sure if I understand correctly. Now the Scale function has "active" pods and "active" pvcs as parameters. If the pod is in terminating state, it's a little hard to get it except I have another function to get all pods.

@willise
Copy link
Contributor Author

willise commented Nov 2, 2022

@willise If the Pod is in the Terminating, it is still risky to delete the PVC directly. The difficulty with this way is that we can't quite tell if it's a normal process or a Hang. I agree with @FillZpp 's idea of adding AlwaysCreatePVC in spec.scaleStrategy to decide whether it should reuse the instanceId of existing free PVCs when creating new Pod.

I got what you mean and I think it is a good advice. But if AlwaysCreatePVC is set, cloneset controller only creates new pod with new PVC. So what to do with existing free PVCs? Like mentioned in the issue, should cloneset controller leave these PVCs unprocessed? @zmberg

@zmberg
Copy link
Member

zmberg commented Nov 2, 2022

Your current cleanup logic works, except that you need to add an additional judgment that only Pods that really don't exist anymore can be cleaned up.

@willise willise force-pushed the fix/enable-clean-up-pvc branch from a447a1a to 0b57d3f Compare November 2, 2022 13:53
@kruise-bot kruise-bot added size/L size/L: 100-499 and removed size/M size/M: 30-99 labels Nov 2, 2022
@willise
Copy link
Contributor Author

willise commented Nov 3, 2022

Also I find the main logic when scaling in, pod deletes the pvc directly. Maybe I can update the ownerreference of the pod from cloneset to the pod and if the pod is deleted, pvc will be deleted by background cascading deletion later after the pod disappears finally. Just like https://github.com/kubernetes/kubernetes/blob/4086b45af3761d59cb82af6ee427d2d6557c1cbc/pkg/controller/statefulset/stateful_set_utils.go#L231 does.

@FillZpp
Copy link
Member

FillZpp commented Nov 4, 2022

Also I find the main logic when scaling in, pod deletes the pvc directly. Maybe I can update the ownerreference of the pod from cloneset to the pod and if the pod is deleted, pvc will be deleted by background cascading deletion later after the pod disappears finally. Just like https://github.com/kubernetes/kubernetes/blob/4086b45af3761d59cb82af6ee427d2d6557c1cbc/pkg/controller/statefulset/stateful_set_utils.go#L231 does.

+1, I think it's a good idea. WDYT @zmberg @veophi

@zmberg
Copy link
Member

zmberg commented Nov 7, 2022

Also I find the main logic when scaling in, pod deletes the pvc directly. Maybe I can update the ownerreference of the pod from cloneset to the pod and if the pod is deleted, pvc will be deleted by background cascading deletion later after the pod disappears finally. Just like https://github.com/kubernetes/kubernetes/blob/4086b45af3761d59cb82af6ee427d2d6557c1cbc/pkg/controller/statefulset/stateful_set_utils.go#L231 does.

Good idea, and please add UT.

@willise willise force-pushed the fix/enable-clean-up-pvc branch from 0b57d3f to 516cda9 Compare November 7, 2022 12:18
@willise willise force-pushed the fix/enable-clean-up-pvc branch 2 times, most recently from 4965c17 to 897bde2 Compare November 9, 2022 09:27
@willise
Copy link
Contributor Author

willise commented Nov 9, 2022

@zmberg @FillZpp I finish the code and please review :).

@willise willise force-pushed the fix/enable-clean-up-pvc branch 2 times, most recently from d3f36cc to 854616b Compare November 24, 2022 07:53
// the existing pvc first. Then it looks like the pod
// is deleted by controller, new pod can be created.
if updateCS.Spec.ScaleStrategy.DisablePVCReuse {
uselessPVCs := getUselessPVCs(pods, pvcs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove uselessPVCs in pvcs? then, pvcs only contains used pvcs.

Copy link
Contributor Author

@willise willise Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zmberg If there are uselessPVCs, cleanupPVCs should always set modified to true then return, so maybe there is no need to update pvcs?

}

for _, pvc := range uselessPVCs {
if clonesetutils.IsTerminating(pvc) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it’s necessary to getInactivePods in the front, just get the pod here, update the owner ref if it exists, delete it if it doesn’t exist.


func updateClaimOwnerRefToPod(pvc *v1.PersistentVolumeClaim, cs *appsv1alpha1.CloneSet, pod *v1.Pod) bool {
needsUpdate := false
updateMeta := func(tm *metav1.TypeMeta) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use metav1.NewControllerRef() and you can realize the common function in utils like https://github.com/openkruise/rollouts/blob/master/pkg/util/condition.go.

@willise willise force-pushed the fix/enable-clean-up-pvc branch 2 times, most recently from 852a53c to 74de5e1 Compare December 22, 2022 08:48
@kruise-bot kruise-bot added size/XL size/XL: 500-999 and removed size/L size/L: 100-499 labels Dec 22, 2022
@willise willise force-pushed the fix/enable-clean-up-pvc branch from 74de5e1 to df1f121 Compare December 22, 2022 09:15
@willise willise requested review from zmberg and removed request for furykerry and hellolijj December 23, 2022 02:47
activeIDs := getInstanceIDsFromPods(pods)

useless := map[string]*v1.PersistentVolumeClaim{}
for _, pvc := range pvcs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writing in this way may have some problems with pointers. The suggestions are as follows:

        for i := range pvcs {
		pvc := pvcs[i]
		id := clonesetutils.GetInstanceID(pvc)
		if id != "" && !activeIDs.Has(id) {
			useless[id] = pvc
		}
	}

// GetAllPods returns all pods in this namespace.
func GetAllPods(reader client.Reader, opts *client.ListOptions) ([]*v1.Pod, error) {
podList := &v1.PodList{}
if err := reader.List(context.TODO(), podList, opts); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if err := reader.List(context.TODO(), podList, opts, , utilclient.DisableDeepCopy); err != nil {

}
ownerRefs := append(
target.GetOwnerReferences(),
metav1.OwnerReference{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*metav1.NewControllerRef(owner, ownerType.GroupVersionKind()))

pkg/util/pods.go Outdated
@@ -343,3 +343,12 @@ func SetPodReadyCondition(pod *v1.Pod) {

SetPodCondition(pod, newPodReady)
}

func UpdatePodMeta(tm *metav1.TypeMeta) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove the function.

needsUpdate = util.RemoveOwnerRef(pvc, cs)
podMeta := &pod.TypeMeta
util.UpdatePodMeta(podMeta)
return util.SetOwnerRef(pvc, pod, podMeta) || needsUpdate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return util.SetOwnerRef(pvc, pod, metav1.TypeMeta{Kind: "Pod", APIVersion: "v1"}) || needsUpdate

return true
}

func SetOwnerRef(target, owner metav1.Object, ownerType *metav1.TypeMeta) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func SetOwnerRef(target, owner metav1.Object, ownerType metav1.TypeMeta) bool {

instanceID := clonesetutils.GetInstanceID(pod)
if pvc, ok := uselessPVCs[instanceID]; ok {
if updateClaimOwnerRefToPod(pvc, cs, pod) {
if modified, err := r.updatePVC(cs, pvc); err != nil && !errors.IsNotFound(err) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if modified, err = r.updatePVC(cs, pvc); err != nil && !errors.IsNotFound(err) {

// If useless pvc owner pod does not exist, the pvc can be deleted directly,
// else update pvc's ownerreference to pod.
for _, pod := range pods {
instanceID := clonesetutils.GetInstanceID(pod)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if kubecontroller.IsPodActive(pod) {
	continue
}


for _, pvc := range uselessPVCs {
// It's safe to delete pvc that has no pod found.
if modified, err := r.deletePVC(cs, pvc); err != nil && !errors.IsNotFound(err) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if modified, err = r.deletePVC(cs, pvc); err != nil && !errors.IsNotFound(err) {

@zmberg
Copy link
Member

zmberg commented Dec 23, 2022

@willise In addition, Can you add e2e for this?

@@ -93,6 +93,10 @@ 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"`

// Indicate if cloneset will reuse aleady existed pvc to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aleady -> already

return nil, err
}

// Ignore inactive pods
var activePods []*v1.Pod
for i, pod := range podList.Items {
for i, pod := range podList {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very worried that there will be problems with pointers, so I suggest:

       for i := range podList {
		pod := podList[i]
		// Consider all rebuild pod as active pod, should not recreate
		if kubecontroller.IsPodActive(pod) {
			activePods = append(activePods, pod)
		}
	}

@@ -0,0 +1,154 @@
/*
Copyright 2020 The Kruise Authors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright 2022 The Kruise Authors.

@@ -0,0 +1,66 @@
/*
Copyright 2021 The Kruise Authors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright 2022 The Kruise Authors.

pkg/controller/cloneset/sync/cloneset_scale.go Outdated Show resolved Hide resolved
pkg/controller/cloneset/sync/cloneset_scale.go Outdated Show resolved Hide resolved
pkg/controller/cloneset/sync/cloneset_scale.go Outdated Show resolved Hide resolved
@willise willise force-pushed the fix/enable-clean-up-pvc branch from df1f121 to 6871ed3 Compare December 26, 2022 13:22
@willise willise force-pushed the fix/enable-clean-up-pvc branch from 6871ed3 to ec8d173 Compare December 29, 2022 13:03
@kruise-bot kruise-bot added size/L size/L: 100-499 and removed size/XL size/XL: 500-999 labels Dec 29, 2022
@furykerry
Copy link
Member

/lgtm

@furykerry
Copy link
Member

/approve

@kruise-bot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: furykerry

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kruise-bot kruise-bot merged commit 7b23f68 into openkruise:master Jan 3, 2023
@willise willise changed the title enable mcloneset deleting pvc when pod hanging enable cloneset deleting pvc when pod hanging Jan 4, 2023
ppbits pushed a commit to ppbits/kruise that referenced this pull request Apr 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] cloneset reuse terminating pod's name when pvc exists
7 participants