...

Source file src/k8s.io/kubernetes/pkg/controller/deployment/recreate.go

Documentation: k8s.io/kubernetes/pkg/controller/deployment

     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  }
   133  

View as plain text