k8s.io/kubernetes@v1.29.3/pkg/controller/deployment/recreate.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package deployment 18 19 import ( 20 "context" 21 apps "k8s.io/api/apps/v1" 22 v1 "k8s.io/api/core/v1" 23 "k8s.io/apimachinery/pkg/types" 24 "k8s.io/kubernetes/pkg/controller" 25 "k8s.io/kubernetes/pkg/controller/deployment/util" 26 ) 27 28 // rolloutRecreate implements the logic for recreating a replica set. 29 func (dc *DeploymentController) rolloutRecreate(ctx context.Context, d *apps.Deployment, rsList []*apps.ReplicaSet, podMap map[types.UID][]*v1.Pod) error { 30 // Don't create a new RS if not already existed, so that we avoid scaling up before scaling down. 31 newRS, oldRSs, err := dc.getAllReplicaSetsAndSyncRevision(ctx, d, rsList, false) 32 if err != nil { 33 return err 34 } 35 allRSs := append(oldRSs, newRS) 36 activeOldRSs := controller.FilterActiveReplicaSets(oldRSs) 37 38 // scale down old replica sets. 39 scaledDown, err := dc.scaleDownOldReplicaSetsForRecreate(ctx, activeOldRSs, d) 40 if err != nil { 41 return err 42 } 43 if scaledDown { 44 // Update DeploymentStatus. 45 return dc.syncRolloutStatus(ctx, allRSs, newRS, d) 46 } 47 48 // Do not process a deployment when it has old pods running. 49 if oldPodsRunning(newRS, oldRSs, podMap) { 50 return dc.syncRolloutStatus(ctx, allRSs, newRS, d) 51 } 52 53 // If we need to create a new RS, create it now. 54 if newRS == nil { 55 newRS, oldRSs, err = dc.getAllReplicaSetsAndSyncRevision(ctx, d, rsList, true) 56 if err != nil { 57 return err 58 } 59 allRSs = append(oldRSs, newRS) 60 } 61 62 // scale up new replica set. 63 if _, err := dc.scaleUpNewReplicaSetForRecreate(ctx, newRS, d); err != nil { 64 return err 65 } 66 67 if util.DeploymentComplete(d, &d.Status) { 68 if err := dc.cleanupDeployment(ctx, oldRSs, d); err != nil { 69 return err 70 } 71 } 72 73 // Sync deployment status. 74 return dc.syncRolloutStatus(ctx, allRSs, newRS, d) 75 } 76 77 // scaleDownOldReplicaSetsForRecreate scales down old replica sets when deployment strategy is "Recreate". 78 func (dc *DeploymentController) scaleDownOldReplicaSetsForRecreate(ctx context.Context, oldRSs []*apps.ReplicaSet, deployment *apps.Deployment) (bool, error) { 79 scaled := false 80 for i := range oldRSs { 81 rs := oldRSs[i] 82 // Scaling not required. 83 if *(rs.Spec.Replicas) == 0 { 84 continue 85 } 86 scaledRS, updatedRS, err := dc.scaleReplicaSetAndRecordEvent(ctx, rs, 0, deployment) 87 if err != nil { 88 return false, err 89 } 90 if scaledRS { 91 oldRSs[i] = updatedRS 92 scaled = true 93 } 94 } 95 return scaled, nil 96 } 97 98 // oldPodsRunning returns whether there are old pods running or any of the old ReplicaSets thinks that it runs pods. 99 func oldPodsRunning(newRS *apps.ReplicaSet, oldRSs []*apps.ReplicaSet, podMap map[types.UID][]*v1.Pod) bool { 100 if oldPods := util.GetActualReplicaCountForReplicaSets(oldRSs); oldPods > 0 { 101 return true 102 } 103 for rsUID, podList := range podMap { 104 // If the pods belong to the new ReplicaSet, ignore. 105 if newRS != nil && newRS.UID == rsUID { 106 continue 107 } 108 for _, pod := range podList { 109 switch pod.Status.Phase { 110 case v1.PodFailed, v1.PodSucceeded: 111 // Don't count pods in terminal state. 112 continue 113 case v1.PodUnknown: 114 // v1.PodUnknown is a deprecated status. 115 // This logic is kept for backward compatibility. 116 // This used to happen in situation like when the node is temporarily disconnected from the cluster. 117 // If we can't be sure that the pod is not running, we have to count it. 118 return true 119 default: 120 // Pod is not in terminal phase. 121 return true 122 } 123 } 124 } 125 return false 126 } 127 128 // scaleUpNewReplicaSetForRecreate scales up new replica set when deployment strategy is "Recreate". 129 func (dc *DeploymentController) scaleUpNewReplicaSetForRecreate(ctx context.Context, newRS *apps.ReplicaSet, deployment *apps.Deployment) (bool, error) { 130 scaled, _, err := dc.scaleReplicaSetAndRecordEvent(ctx, newRS, *(deployment.Spec.Replicas), deployment) 131 return scaled, err 132 }