Sticky sessions and canary releases in Kubernetes
Tags: kubernetes, devops
Published: 2023-06-19 12:17:23

Sticky sessions or session affinity is a convenient strategy to keep subsequent requests always reaching the same pod.

Let's look at how it works by deploying a sample application with three replicas and one service.

In this scenario, **requests directed to the service are load-balanced amongst the available replicas.**

![A deployment and a service in Kubernetes](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-2_m4unrn.png)

Let's deploy the [ingress-nginx controller](https://github.com/kubernetes/ingress-nginx) and create an Ingress manifest for the deployment.

In this case, **the ingress controller skips the services** and load balances the traffic directly to the pods.

![A deployment, a service and ingress controller in Kubernetes](https://res.cloudinary.com/learnk8s/image/upload/v1687158033/threads/sticky-3_bubeg0.png)

While the two scenarios end up with the same outcome (i.e. requests are distributed to all replicas), there's a subtle (but essential) distinction: **the Service operates on L4 (TCP/UDP), whereas the Ingress is L7 (HTTP).**

![Difference between Kubernetes service and ingress controller](https://res.cloudinary.com/learnk8s/image/upload/v1687158033/threads/sticky-4_pjzvvg.png)

**Unlike the service, the Ingress controller can route traffic based on paths, headers, etc.**

You can also use it to define weights (e.g. 20-80 traffic split) or sticky sessions (all requests from the same origin always land on the same pod).

![Sticky sessions, weighted traffic and canary release in an Ingress controller](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-5_p4yqf4.png)

The following Ingress implements **sticky sessions for the nginx-ingress controller.**

The ingress writes a cookie on your browser to keep track of what instance you visited.

![Session affinity in ingress-nginx](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-6_sbpwle.png)

There are two convenient settings for affinity:

1. **balanced** — requests are redistributed if the deployment scales up.
2. **persistent** — no matter what, the requests always stick to the same pod.

**nginx-ingress can also be used for canary releases.**

If you have two deployments and you wish to test a subset of the traffic for a newer version of that deployment, you can do so with a canary release (and impact a minimal amount of users).

![A canary release with ingress-nginx](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-8_ebkju9.png)

**In a canary release, each deployment has its own Ingress manifest.**

However, one of those is labelled as a canary.

You can decide how the traffic is forwarded: for example, you could inspect a header or cookie.

![Canary release beased on a header value](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-9_s5g811.png)

In this example, all traffic labelled east-us is routed to the canary deployment.

![Example of routing traffic with a canary release](https://res.cloudinary.com/learnk8s/image/upload/v1687158035/threads/sticky-10_c3nu9n.png)

You can also decide which fraction of the total traffic is routed to the canary with weights.

![Setting weights to a canary release](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-11_ymwlj7.png)

But if the header is omitted in a subsequent request, the user will return to see the previous deployment.

_How can you fix that?_

![Traffic in canary releases is not sticky](https://res.cloudinary.com/learnk8s/image/upload/v1687158034/threads/sticky-12_llofbe.png)

_With sticky sessions!_

**You can combine canary releases and sticky sessions with ingress-nginx to progressively (and safely) roll out new deployments to your users.**

![Combining canary releases and sticky sessions](https://res.cloudinary.com/learnk8s/image/upload/v1687158035/threads/sticky-13_vvrcgl.png)

It's important to remember that those types of canary releases are only possible for front-facing apps.

To roll out a canary release for internal microservices, you should look at alternatives (e.g. service mesh).

![Traffic to internal services is not forwarded by the ingress controller](https://res.cloudinary.com/learnk8s/image/upload/v1687158035/threads/sticky-14_bfkjit.png)

_Is nginx-ingress the only option for sticky sessions and canary releases?_

Not really, but the annotations might be different to other ingress controllers.

[At Learnk8s, we've put together a spreadsheet to compare them.](https://docs.google.com/spreadsheets/d/191WWNpjJ2za6-nbG4ZoUMXMpUK8KlCIosvQB0f-oq3k)

And finally, if you've enjoyed this thread, you might also like:

- [The Kubernetes workshops that we run at Learnk8s.](https://learnk8s.io/training)
- [This collection of past threads.](https://twitter.com/danielepolencic/status/1298543151901155330)
- [The Kubernetes newsletter I publish every week.](https://learnk8s.io/learn-kubernetes-weekly)

While authoring this post, I also found the following resources valuable:

- [Configure a canary deployment](https://docs.mirantis.com/mke/3.6/ops/deploy-apps-k8s/nginx-ingress/configure-canary-deployment.html)
- [Sticky sessions/Session Affinity based on Nginx Ingress](https://help.ovhcloud.com/csm/en-sg-public-cloud-kubernetes-sticky-session-nginx-ingress?id=kb_article_view&sysparm_article=KB0049968)
- [Session Affinity and Kubernetes— Proceed With Caution!](https://pauldally.medium.com/session-affinity-and-kubernetes-proceed-with-caution-8e66fd5deb05)
- [Session Affinity](https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#session-affinity)