Skip to content

Commit 0d11770

Browse files
[release-1.16] Shift traffic when the minimum number of replicas are ready during progressive rollout (#314)
* Shift traffic when the minimum number of replicas are ready during progressive rollout Fixes: #302 * Verify if the target replicas is nil * Added the test cases * Clean up the logic for the routeLister * Check the final revision name --------- Co-authored-by: Vincent Hou <[email protected]>
1 parent dcb002c commit 0d11770

File tree

3 files changed

+345
-45
lines changed

3 files changed

+345
-45
lines changed

pkg/reconciler/service/resources/rolloutorchestrator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ func GetInitialTargetRevision(service *servingv1.Service, config *servingv1.Conf
197197
}
198198

199199
// consolidateTraffic consolidates traffic with the same revision name into one.
200-
func consolidateTraffic(traffic []servingv1.TrafficTarget) []servingv1.TrafficTarget {
200+
func consolidateTraffic(trafficTargets []servingv1.TrafficTarget) []servingv1.TrafficTarget {
201201
trafficMap := map[string]*servingv1.TrafficTarget{}
202-
for _, traffic := range traffic {
202+
for _, traffic := range trafficTargets {
203203
if trafficInMap, found := trafficMap[traffic.RevisionName]; !found {
204204
trafficMap[traffic.RevisionName] = traffic.DeepCopy()
205205
} else {

pkg/reconciler/service/service.go

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, service *servingv1.Servi
162162
}
163163

164164
// After the RolloutOrchestrator is created or updated, call the base reconciliation loop of the service.
165-
err = c.baseReconciler.ReconcileKind(ctx, TransformService(service, rolloutOrchestrator, c.rolloutConfig))
165+
err = c.baseReconciler.ReconcileKind(ctx, TransformService(service, rolloutOrchestrator, c.rolloutConfig, c.spaLister.StagePodAutoscalers(service.Namespace),
166+
c.routeLister.Routes(service.Namespace)))
166167
if err != nil {
167168
return err
168169
}
@@ -909,19 +910,76 @@ func calculateStageTargetRevisions(replicasMap map[string]int32, startRevisions
909910
return stageRevisionTarget
910911
}
911912

912-
func TransformService(service *servingv1.Service, ro *v1.RolloutOrchestrator, rc *RolloutConfig) *servingv1.Service {
913+
func TransformService(service *servingv1.Service, ro *v1.RolloutOrchestrator, rc *RolloutConfig,
914+
spaLister listers.StagePodAutoscalerNamespaceLister, routeLister servinglisters.RouteNamespaceLister) *servingv1.Service {
913915
// If Knative Service defines more than one traffic, this feature tentatively does not cover this case.
914916
if len(service.Spec.Traffic) > 1 {
915917
return service
916918
}
917919
service.Spec.RouteSpec = servingv1.RouteSpec{
918-
Traffic: convertIntoTrafficTarget(service.GetName(), ro, rc),
920+
Traffic: convertIntoTrafficTarget(service.GetName(), ro, rc, spaLister, routeLister),
919921
}
920922
return service
921923
}
922924

923-
func convertIntoTrafficTarget(name string, ro *v1.RolloutOrchestrator, rc *RolloutConfig) []servingv1.TrafficTarget {
925+
func convertIntoTrafficTarget(name string, ro *v1.RolloutOrchestrator, rc *RolloutConfig,
926+
spaLister listers.StagePodAutoscalerNamespaceLister, routeLister servinglisters.RouteNamespaceLister) []servingv1.TrafficTarget {
924927
revisionTarget := ro.Spec.StageTargetRevisions
928+
finalTargetRevs := ro.Spec.TargetRevisions
929+
targetRevName := finalTargetRevs[0].RevisionName
930+
if !ro.IsNotConvertToOneUpgrade() && rc.ProgressiveRolloutEnabled {
931+
// The revisionTarget is set directly to ro.Spec.StageTargetRevisions, because this is not a
932+
// one-to-one revision upgrade or the rollout feature is disabled. We do not cover this use case
933+
// in the implementation. The traffic target is set directly configured in ro.Spec.StageTargetRevisions.
934+
// However, if this is one-to-one or many-to-one rollout, we need to make sure the minimum number of
935+
// replicas are met before shifting the traffic percentage over.
936+
// Find out the name of the revision scaling up. Get the name of the spa for the revision scaling up.
937+
// The name is the same as the revision name.
938+
spaTargetRevName := targetRevName
939+
targetNumberReplicas, minScale := finalTargetRevs[0].MinScale, finalTargetRevs[0].MinScale
940+
941+
// Find the target number of replicas for the current stage.
942+
for _, revision := range ro.Spec.StageTargetRevisions {
943+
if revision.RevisionName == spaTargetRevName && revision.TargetReplicas != nil {
944+
targetNumberReplicas = revision.TargetReplicas
945+
}
946+
}
947+
spa, err := spaLister.Get(spaTargetRevName)
948+
// Check the number of replicas has reached the target number of replicas for the revision scaling up
949+
if err == nil && targetNumberReplicas != nil && spa.Status.ActualScale != nil && minScale != nil &&
950+
*spa.Status.ActualScale < *minScale && *spa.Status.ActualScale < *targetNumberReplicas {
951+
// If we have issues getting the spa, or the number of the replicas has reached the target number of
952+
// the revision to scale up, we set the revisionTarget to ro.Spec.StageTargetRevisions.
953+
954+
// However, if there is no issue getting yhe spa, and the actual number of replicas is less than
955+
// the target number of replicas, we need to use ro.Status.StageRevisionStatus or route.Status.Traffic
956+
// as the traffic information for the route.
957+
if len(ro.Status.StageRevisionStatus) > 0 {
958+
// If the ro has the StageRevisionStatus in the status, use it.
959+
revisionTarget = ro.Status.StageRevisionStatus
960+
for index := range revisionTarget {
961+
if revisionTarget[index].RevisionName == spaTargetRevName {
962+
continue
963+
}
964+
revisionTarget[index].LatestRevision = ptr.Bool(false)
965+
}
966+
} else {
967+
// If the ro does not have the StageRevisionStatus in the status, use the existing one in route.
968+
route, errRoute := routeLister.Get(ro.Name)
969+
if errRoute == nil && len(route.Status.Traffic) > 0 {
970+
traffics := route.Status.Traffic
971+
for index := range traffics {
972+
if traffics[index].RevisionName == spaTargetRevName {
973+
continue
974+
}
975+
traffics[index].LatestRevision = ptr.Bool(false)
976+
}
977+
return traffics
978+
}
979+
}
980+
}
981+
}
982+
925983
trafficTarget := make([]servingv1.TrafficTarget, 0, len(revisionTarget))
926984
for _, revision := range revisionTarget {
927985
target := servingv1.TrafficTarget{}
@@ -948,6 +1006,8 @@ func convertIntoTrafficTarget(name string, ro *v1.RolloutOrchestrator, rc *Rollo
9481006
}
9491007

9501008
if revision.LatestRevision != nil && *revision.LatestRevision {
1009+
// No matter the RevisionName is available for the latest revision or not, we cannot
1010+
// set the RevisionName here. Only ConfigurationName is allowed.
9511011
if strings.TrimSpace(revision.ConfigurationName) != "" {
9521012
target.ConfigurationName = revision.ConfigurationName
9531013
} else {

0 commit comments

Comments
 (0)