Commit ca061574 authored by k8s-merge-robot's avatar k8s-merge-robot Committed by GitHub

Merge pull request #28162 from kargakis/annotation-fixes-for-scaling

Automatic merge from submit-queue controller: update all rs annotations on a scaled rollout Closes https://github.com/kubernetes/kubernetes/issues/28145 @kubernetes/deployment
parents 27bb99d4 97b9c73b
...@@ -499,7 +499,11 @@ func (dc *DeploymentController) syncDeployment(key string) error { ...@@ -499,7 +499,11 @@ func (dc *DeploymentController) syncDeployment(key string) error {
} }
} }
if dc.isScalingEvent(d) { scalingEvent, err := dc.isScalingEvent(d)
if err != nil {
return err
}
if scalingEvent {
return dc.sync(d) return dc.sync(d)
} }
......
...@@ -510,15 +510,26 @@ func (dc *DeploymentController) updateDeploymentStatus(allRSs []*extensions.Repl ...@@ -510,15 +510,26 @@ func (dc *DeploymentController) updateDeploymentStatus(allRSs []*extensions.Repl
// isScalingEvent checks whether the provided deployment has been updated with a scaling event // isScalingEvent checks whether the provided deployment has been updated with a scaling event
// by looking at the desired-replicas annotation in the active replica sets of the deployment. // by looking at the desired-replicas annotation in the active replica sets of the deployment.
func (dc *DeploymentController) isScalingEvent(d *extensions.Deployment) bool { func (dc *DeploymentController) isScalingEvent(d *extensions.Deployment) (bool, error) {
newRS, oldRSs, err := dc.getAllReplicaSetsAndSyncRevision(d, false) newRS, oldRSs, err := dc.getAllReplicaSetsAndSyncRevision(d, false)
if err != nil { if err != nil {
return false return false, err
} }
// If there is no new replica set matching this deployment and the deployment isn't paused // If there is no new replica set matching this deployment and the deployment isn't paused
// then there is a new rollout that waits to happen // then there is a new rollout that waits to happen
if newRS == nil && !d.Spec.Paused { if newRS == nil && !d.Spec.Paused {
return false // Update all active replicas sets to the new deployment size. SetReplicasAnnotations makes
// sure that we will update only replica sets that don't have the current size of the deployment.
maxSurge := deploymentutil.MaxSurge(*d)
for _, rs := range controller.FilterActiveReplicaSets(oldRSs) {
if updated := deploymentutil.SetReplicasAnnotations(rs, d.Spec.Replicas, d.Spec.Replicas+maxSurge); updated {
if _, err := dc.client.Extensions().ReplicaSets(rs.Namespace).Update(rs); err != nil {
glog.Infof("Cannot update annotations for replica set %q: %v", rs.Name, err)
return false, err
}
}
}
return false, nil
} }
allRSs := append(oldRSs, newRS) allRSs := append(oldRSs, newRS)
for _, rs := range controller.FilterActiveReplicaSets(allRSs) { for _, rs := range controller.FilterActiveReplicaSets(allRSs) {
...@@ -527,8 +538,8 @@ func (dc *DeploymentController) isScalingEvent(d *extensions.Deployment) bool { ...@@ -527,8 +538,8 @@ func (dc *DeploymentController) isScalingEvent(d *extensions.Deployment) bool {
continue continue
} }
if desired != d.Spec.Replicas { if desired != d.Spec.Replicas {
return true return true, nil
} }
} }
return false return false, nil
} }
...@@ -3155,14 +3155,17 @@ func waitForReplicaSetPodsGone(c *client.Client, rs *extensions.ReplicaSet) erro ...@@ -3155,14 +3155,17 @@ func waitForReplicaSetPodsGone(c *client.Client, rs *extensions.ReplicaSet) erro
// Waits for the deployment to reach desired state. // Waits for the deployment to reach desired state.
// Returns an error if minAvailable or maxCreated is broken at any times. // Returns an error if minAvailable or maxCreated is broken at any times.
func WaitForDeploymentStatus(c clientset.Interface, ns, deploymentName string, desiredUpdatedReplicas, minAvailable, maxCreated, minReadySeconds int32) error { func WaitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment, expectComplete bool) error {
var oldRSs, allOldRSs, allRSs []*extensions.ReplicaSet var (
var newRS *extensions.ReplicaSet oldRSs, allOldRSs, allRSs []*extensions.ReplicaSet
var deployment *extensions.Deployment newRS *extensions.ReplicaSet
err := wait.Poll(Poll, 5*time.Minute, func() (bool, error) { deployment *extensions.Deployment
reason string
)
err := wait.Poll(Poll, 2*time.Minute, func() (bool, error) {
var err error var err error
deployment, err = c.Extensions().Deployments(ns).Get(deploymentName) deployment, err = c.Extensions().Deployments(d.Namespace).Get(d.Name)
if err != nil { if err != nil {
return false, err return false, err
} }
...@@ -3172,47 +3175,57 @@ func WaitForDeploymentStatus(c clientset.Interface, ns, deploymentName string, d ...@@ -3172,47 +3175,57 @@ func WaitForDeploymentStatus(c clientset.Interface, ns, deploymentName string, d
} }
if newRS == nil { if newRS == nil {
// New RC hasn't been created yet. // New RC hasn't been created yet.
reason = "new replica set hasn't been created yet"
return false, nil return false, nil
} }
allRSs = append(oldRSs, newRS) allRSs = append(oldRSs, newRS)
// The old/new ReplicaSets need to contain the pod-template-hash label // The old/new ReplicaSets need to contain the pod-template-hash label
for i := range allRSs { for i := range allRSs {
if !labelsutil.SelectorHasLabel(allRSs[i].Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey) { if !labelsutil.SelectorHasLabel(allRSs[i].Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey) {
reason = "all replica sets need to contain the pod-template-hash label"
return false, nil return false, nil
} }
} }
totalCreated := deploymentutil.GetReplicaCountForReplicaSets(allRSs) totalCreated := deploymentutil.GetReplicaCountForReplicaSets(allRSs)
totalAvailable, err := deploymentutil.GetAvailablePodsForDeployment(c, deployment, minReadySeconds) totalAvailable, err := deploymentutil.GetAvailablePodsForDeployment(c, deployment, deployment.Spec.MinReadySeconds)
if err != nil { if err != nil {
return false, err return false, err
} }
maxCreated := deployment.Spec.Replicas + deploymentutil.MaxSurge(*deployment)
if totalCreated > maxCreated { if totalCreated > maxCreated {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS) reason = fmt.Sprintf("total pods created: %d, more than the max allowed: %d", totalCreated, maxCreated)
logPodsOfDeployment(c, deployment, minReadySeconds) Logf(reason)
return false, fmt.Errorf("total pods created: %d, more than the max allowed: %d", totalCreated, maxCreated) return false, nil
} }
minAvailable := deployment.Spec.Replicas - deploymentutil.MaxUnavailable(*deployment)
if totalAvailable < minAvailable { if totalAvailable < minAvailable {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS) reason = fmt.Sprintf("total pods available: %d, less than the min required: %d", totalAvailable, minAvailable)
logPodsOfDeployment(c, deployment, minReadySeconds) Logf(reason)
return false, fmt.Errorf("total pods available: %d, less than the min required: %d", totalAvailable, minAvailable) return false, nil
}
if !expectComplete {
return true, nil
} }
// When the deployment status and its underlying resources reach the desired state, we're done // When the deployment status and its underlying resources reach the desired state, we're done
if deployment.Status.Replicas == desiredUpdatedReplicas && if deployment.Status.Replicas == deployment.Spec.Replicas &&
deployment.Status.UpdatedReplicas == desiredUpdatedReplicas && deployment.Status.UpdatedReplicas == deployment.Spec.Replicas &&
deploymentutil.GetReplicaCountForReplicaSets(oldRSs) == 0 && deploymentutil.GetReplicaCountForReplicaSets(oldRSs) == 0 &&
deploymentutil.GetReplicaCountForReplicaSets([]*extensions.ReplicaSet{newRS}) == desiredUpdatedReplicas { deploymentutil.GetReplicaCountForReplicaSets([]*extensions.ReplicaSet{newRS}) == deployment.Spec.Replicas {
return true, nil return true, nil
} }
reason = fmt.Sprintf("deployment %q is yet to complete: %#v", deployment.Name, deployment.Status)
return false, nil return false, nil
}) })
if err == wait.ErrWaitTimeout { if err == wait.ErrWaitTimeout {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS) logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment, minReadySeconds) logPodsOfDeployment(c, deployment, deployment.Spec.MinReadySeconds)
err = fmt.Errorf("%s", reason)
} }
if err != nil { if err != nil {
return fmt.Errorf("error waiting for deployment %s status to match expectation: %v", deploymentName, err) return fmt.Errorf("error waiting for deployment %q status to match expectation: %v", d.Name, err)
} }
return nil return nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment