Successfully using Ingress-NGINX and SessionAffinity with Regex paths
First, please consider enhancing your application so that it doesn’t require session affinity!
The Problem
If you absolutely must move forward with session affinity using Ingress-NGINX Controller, you may find that it doesn’t work initially. Consider the following Ingress object:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helloworld-deployment-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/affinity: "cookie"
spec:
ingressClassName: myingressclass
rules:
- http:
paths:
- path: /helloworld/(.*)
pathType: Prefix
backend:
service:
name: helloworld-deployment-svc
port:
number: 8080
When this Ingress is accessed, your first request is handled by one Pod:
Hello, world!
Hostname: helloworld-deployment-cdc7bf697-9rnbb
and your next request might be handled by another Pod:
Hello, world!
Hostname: helloworld-deployment-cdc7bf697-r79kj
Persistence (stickiness) is clearly not working!
The issue is how Ingress-NGINX is creating the cookie (you can see this, for example, with Chrome Developer Tools — Ctrl-Shift-I):
Set-Cookie: INGRESSCOOKIE=1683294502.046.28868.397950|a70374fa4f94f7a90dd3fcc9411153f9;
Path=/helloworld/(.*); HttpOnly
Because the Path attribute doesn’t match the URL the browser sees (cookie Path matching doesn’t use regular expressions, and so the (.*) would have to literally match the content of the URL), on the next request the browser does not send the cookie — effectively disabling session affinity.
The Solution
The cookie Path is defaulting to the path in the Ingress, which since it is specified as a regex, is not a valid cookie Path. If you add the following annotation, persistence will start working as expected:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helloworld-deployment-ingress
annotations:
nginx.ingress.kubernetes.io/session-cookie-path: /helloworld/
<snip>
The resulting Set-Cookie header will now look like this:
Set-Cookie: INGRESSCOOKIE=1683294502.046.28868.397950|a70374fa4f94f7a90dd3fcc9411153f9;
Path=/helloworld/; HttpOnly
Now that the cookie’s Path attribute actually matches the path that the browser sees, it will start sending the cookie back to the Ingress controller , enabling the Ingress controller to direct the request back to the original Pod.