@@ -155,7 +155,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
155155
156156 // check if virtual service exists
157157 // and if it contains weighted destination routes to the primary and canary services
158- primaryWeight , canaryWeight , err := meshRouter .GetRoutes (cd )
158+ primaryWeight , canaryWeight , mirrored , err := meshRouter .GetRoutes (cd )
159159 if err != nil {
160160 c .recordEventWarningf (cd , "%v" , err )
161161 return
@@ -176,7 +176,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
176176 // route all traffic back to primary
177177 primaryWeight = 100
178178 canaryWeight = 0
179- if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight ); err != nil {
179+ if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight , false ); err != nil {
180180 c .recordEventWarningf (cd , "%v" , err )
181181 return
182182 }
@@ -218,7 +218,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
218218 if cd .Status .Phase == flaggerv1 .CanaryPhasePromoting {
219219 if provider != "kubernetes" {
220220 c .recordEventInfof (cd , "Routing all traffic to primary" )
221- if err := meshRouter .SetRoutes (cd , 100 , 0 ); err != nil {
221+ if err := meshRouter .SetRoutes (cd , 100 , 0 , false ); err != nil {
222222 c .recordEventWarningf (cd , "%v" , err )
223223 return
224224 }
@@ -275,7 +275,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
275275 // route all traffic back to primary
276276 primaryWeight = 100
277277 canaryWeight = 0
278- if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight ); err != nil {
278+ if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight , false ); err != nil {
279279 c .recordEventWarningf (cd , "%v" , err )
280280 return
281281 }
@@ -302,8 +302,9 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
302302 }
303303
304304 // check if the canary success rate is above the threshold
305- // skip check if no traffic is routed to canary
306- if canaryWeight == 0 && cd .Status .Iterations == 0 {
305+ // skip check if no traffic is routed or mirrored to canary
306+ if canaryWeight == 0 && cd .Status .Iterations == 0 &&
307+ (cd .Spec .CanaryAnalysis .Mirror == false || mirrored == false ) {
307308 c .recordEventInfof (cd , "Starting canary analysis for %s.%s" , cd .Spec .TargetRef .Name , cd .Namespace )
308309
309310 // run pre-rollout web hooks
@@ -328,7 +329,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
328329 if len (cd .Spec .CanaryAnalysis .Match ) > 0 && cd .Spec .CanaryAnalysis .Iterations > 0 {
329330 // route traffic to canary and increment iterations
330331 if cd .Spec .CanaryAnalysis .Iterations > cd .Status .Iterations {
331- if err := meshRouter .SetRoutes (cd , 0 , 100 ); err != nil {
332+ if err := meshRouter .SetRoutes (cd , 0 , 100 , false ); err != nil {
332333 c .recordEventWarningf (cd , "%v" , err )
333334 return
334335 }
@@ -372,6 +373,15 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
372373 if cd .Spec .CanaryAnalysis .Iterations > 0 {
373374 // increment iterations
374375 if cd .Spec .CanaryAnalysis .Iterations > cd .Status .Iterations {
376+ // If in "mirror" mode, mirror requests during the entire B/G canary test
377+ if provider != "kubernetes" &&
378+ cd .Spec .CanaryAnalysis .Mirror == true && mirrored == false {
379+ if err := meshRouter .SetRoutes (cd , 100 , 0 , true ); err != nil {
380+ c .recordEventWarningf (cd , "%v" , err )
381+ }
382+ c .logger .With ("canary" , fmt .Sprintf ("%s.%s" , name , namespace )).
383+ Infof ("Enabling mirroring for Blue/Green" )
384+ }
375385 if err := c .deployer .SetStatusIterations (cd , cd .Status .Iterations + 1 ); err != nil {
376386 c .recordEventWarningf (cd , "%v" , err )
377387 return
@@ -390,7 +400,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
390400 if cd .Spec .CanaryAnalysis .Iterations == cd .Status .Iterations {
391401 if provider != "kubernetes" {
392402 c .recordEventInfof (cd , "Routing all traffic to canary" )
393- if err := meshRouter .SetRoutes (cd , 0 , 100 ); err != nil {
403+ if err := meshRouter .SetRoutes (cd , 0 , 100 , false ); err != nil {
394404 c .recordEventWarningf (cd , "%v" , err )
395405 return
396406 }
@@ -429,16 +439,34 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh
429439 if cd .Spec .CanaryAnalysis .StepWeight > 0 {
430440 // increase traffic weight
431441 if canaryWeight < maxWeight {
432- primaryWeight -= cd .Spec .CanaryAnalysis .StepWeight
433- if primaryWeight < 0 {
434- primaryWeight = 0
435- }
436- canaryWeight += cd .Spec .CanaryAnalysis .StepWeight
437- if canaryWeight > 100 {
438- canaryWeight = 100
442+ // If in "mirror" mode, do one step of mirroring before shifting traffic to canary.
443+ // When mirroring, all requests go to primary and canary, but only responses from
444+ // primary go back to the user.
445+ if cd .Spec .CanaryAnalysis .Mirror && canaryWeight == 0 {
446+ if mirrored == false {
447+ mirrored = true
448+ primaryWeight = 100
449+ canaryWeight = 0
450+ } else {
451+ mirrored = false
452+ primaryWeight = 100 - cd .Spec .CanaryAnalysis .StepWeight
453+ canaryWeight = cd .Spec .CanaryAnalysis .StepWeight
454+ }
455+ c .logger .With ("canary" , fmt .Sprintf ("%s.%s" , name , namespace )).
456+ Infof ("Running mirror step %d/%d/%t" , primaryWeight , canaryWeight , mirrored )
457+ } else {
458+
459+ primaryWeight -= cd .Spec .CanaryAnalysis .StepWeight
460+ if primaryWeight < 0 {
461+ primaryWeight = 0
462+ }
463+ canaryWeight += cd .Spec .CanaryAnalysis .StepWeight
464+ if canaryWeight > 100 {
465+ canaryWeight = 100
466+ }
439467 }
440468
441- if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight ); err != nil {
469+ if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight , mirrored ); err != nil {
442470 c .recordEventWarningf (cd , "%v" , err )
443471 return
444472 }
@@ -489,7 +517,7 @@ func (c *Controller) shouldSkipAnalysis(cd *flaggerv1.Canary, meshRouter router.
489517 // route all traffic to primary
490518 primaryWeight = 100
491519 canaryWeight = 0
492- if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight ); err != nil {
520+ if err := meshRouter .SetRoutes (cd , primaryWeight , canaryWeight , false ); err != nil {
493521 c .recordEventWarningf (cd , "%v" , err )
494522 return false
495523 }
0 commit comments