Skip to content

Commit d9d910b

Browse files
authored
Merge pull request #1861 from renatovassaomb/rv/istio-primary-cookie-name-support
Feat: Add support for stickiness for primary deployment in Istio
2 parents 9090802 + 70c4c52 commit d9d910b

15 files changed

Lines changed: 546 additions & 112 deletions

File tree

artifacts/flagger/crd.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,9 @@ spec:
12501250
sessionAffinityCookie:
12511251
description: Session affinity cookie of the current canary run
12521252
type: string
1253+
primarySessionAffinityCookie:
1254+
description: Primary session affinity cookie of the current canary run
1255+
type: string
12531256
previousSessionAffinityCookie:
12541257
description: Session affinity cookie of the previous canary run
12551258
type: string

charts/flagger/crds/crd.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,9 @@ spec:
12501250
sessionAffinityCookie:
12511251
description: Session affinity cookie of the current canary run
12521252
type: string
1253+
primarySessionAffinityCookie:
1254+
description: Primary session affinity cookie of the current canary run
1255+
type: string
12531256
previousSessionAffinityCookie:
12541257
description: Session affinity cookie of the previous canary run
12551258
type: string

docs/gitbook/tutorials/istio-progressive-delivery.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ You can load `app.example.com` in your browser and refresh it until you see the
404404
All subsequent requests after that will be served by `podinfo:6.0.1` and not `podinfo:6.0.0` because of the session affinity
405405
configured by Flagger with Istio.
406406

407+
To configure stickiness for the Primary deployment to ensure fair weighted traffic routing, please
408+
checkout the [deployment strategies docs](../usage/deployment-strategies.md#canary-release-with-session-affinity).
409+
407410
## Traffic mirroring
408411

409412
![Flagger Canary Traffic Shadowing](https://raw.githubusercontent.com/fluxcd/flagger/main/docs/diagrams/flagger-canary-traffic-mirroring.png)

docs/gitbook/usage/deployment-strategies.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ can also configure stickiness for the Primary deployment. You can configure this
474474
primaryCookieName: primary-flagger-cookie
475475
```
476476

477-
> Note: This is only supported for the Gateway API provider for now.
477+
> Note: This is only supported for the Gateway API and Istio providers for now.
478478

479479
Let's understand what the above configuration does. All the session affinity stuff in the above section
480480
still occurs, but now the response header for requests routed to the primary deployment also include a

kustomize/base/flagger/crd.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,9 @@ spec:
12501250
sessionAffinityCookie:
12511251
description: Session affinity cookie of the current canary run
12521252
type: string
1253+
primarySessionAffinityCookie:
1254+
description: Primary session affinity cookie of the current canary run
1255+
type: string
12531256
previousSessionAffinityCookie:
12541257
description: Session affinity cookie of the previous canary run
12551258
type: string

pkg/apis/flagger/v1beta1/canary.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,9 @@ func (c *Canary) DeploymentStrategy() string {
706706
}
707707

708708
// BuildCookie returns the cookie that should be used as the value of a Set-Cookie header
709-
func (s *SessionAffinity) BuildCookie(cookieName string) string {
709+
func (s *SessionAffinity) BuildCookie(cookieName string, maxAge int) string {
710710
cookie := fmt.Sprintf("%s; %s=%d", cookieName, "Max-Age",
711-
s.GetMaxAge(),
711+
maxAge,
712712
)
713713

714714
if s.Domain != "" {

pkg/apis/flagger/v1beta1/status.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ type CanaryStatus struct {
7878
// +optional
7979
SessionAffinityCookie string `json:"sessionAffinityCookie,omitempty"`
8080
// +optional
81+
PrimarySessionAffinityCookie string `json:"primarySessionAffinityCookie,omitempty"`
82+
// +optional
8183
TrackedConfigs *map[string]string `json:"trackedConfigs,omitempty"`
8284
// +optional
8385
LastAppliedSpec string `json:"lastAppliedSpec,omitempty"`

pkg/router/gateway_api.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,10 @@ func (gwr *GatewayAPIRouter) getSessionAffinityRouteRules(canary *flaggerv1.Cana
492492
if canary.Status.SessionAffinityCookie == "" {
493493
canary.Status.SessionAffinityCookie = fmt.Sprintf("%s=%s", canary.Spec.Analysis.SessionAffinity.CookieName, randSeq())
494494
}
495-
primaryCookie := fmt.Sprintf("%s=%s", canary.Spec.Analysis.SessionAffinity.PrimaryCookieName, randSeq())
495+
// if the status doesn't have the primary cookie, then generate a new primary cookie.
496+
if canary.Status.PrimarySessionAffinityCookie == "" {
497+
canary.Status.PrimarySessionAffinityCookie = fmt.Sprintf("%s=%s", canary.Spec.Analysis.SessionAffinity.PrimaryCookieName, randSeq())
498+
}
496499

497500
// add response modifier to the canary backend ref in the rule that does weighted routing
498501
// to include the canary cookie.
@@ -503,7 +506,7 @@ func (gwr *GatewayAPIRouter) getSessionAffinityRouteRules(canary *flaggerv1.Cana
503506
Add: []v1.HTTPHeader{
504507
{
505508
Name: setCookieHeader,
506-
Value: canary.Spec.Analysis.SessionAffinity.BuildCookie(canary.Status.SessionAffinityCookie),
509+
Value: canary.Spec.Analysis.SessionAffinity.BuildCookie(canary.Status.SessionAffinityCookie, canary.Spec.Analysis.SessionAffinity.GetMaxAge()),
507510
},
508511
},
509512
},
@@ -522,10 +525,8 @@ func (gwr *GatewayAPIRouter) getSessionAffinityRouteRules(canary *flaggerv1.Cana
522525
ResponseHeaderModifier: &v1.HTTPHeaderFilter{
523526
Add: []v1.HTTPHeader{
524527
{
525-
Name: setCookieHeader,
526-
Value: fmt.Sprintf("%s; %s=%d", primaryCookie, maxAgeAttr,
527-
int(interval.Seconds()),
528-
),
528+
Name: setCookieHeader,
529+
Value: canary.Spec.Analysis.SessionAffinity.BuildCookie(canary.Status.PrimarySessionAffinityCookie, int(interval.Seconds())),
529530
},
530531
},
531532
},
@@ -566,7 +567,7 @@ func (gwr *GatewayAPIRouter) getSessionAffinityRouteRules(canary *flaggerv1.Cana
566567
// primary cookie and send them to the primary backend, only if a primary cookie name has
567568
// been specified.
568569
if canary.Spec.Analysis.SessionAffinity.PrimaryCookieName != "" {
569-
cookieKeyAndVal = strings.Split(primaryCookie, "=")
570+
cookieKeyAndVal = strings.Split(canary.Status.PrimarySessionAffinityCookie, "=")
570571
regexMatchType = v1.HeaderMatchRegularExpression
571572
primaryCookieMatch := v1.HTTPRouteMatch{
572573
Headers: []v1.HTTPHeaderMatch{

pkg/router/gateway_api_v1beta1.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ func (gwr *GatewayAPIV1Beta1Router) getSessionAffinityRouteRules(canary *flagger
424424
Add: []v1beta1.HTTPHeader{
425425
{
426426
Name: setCookieHeader,
427-
Value: canary.Spec.Analysis.SessionAffinity.BuildCookie(canary.Status.SessionAffinityCookie),
427+
Value: canary.Spec.Analysis.SessionAffinity.BuildCookie(canary.Status.SessionAffinityCookie, canary.Spec.Analysis.SessionAffinity.GetMaxAge()),
428428
},
429429
},
430430
},

0 commit comments

Comments
 (0)