Stateful session filter
Set up strong stickiness for upstream services with the Envoy Stateful Session filter.
About session affinity
Session affinity, also referred to as sticky session, allows you to route requests for a particular session to the same upstream service instance that served the initial request. This setup is particularly useful if you have an upstream service that performs expensive operations and caches the output or data for subsequent requests. With session affinity, you make sure that the expensive operation is performed once and that subsequent requests can be served from the upstream’s cache, which can significantly improve operational cost and response times for your clients.
About the stateful session filter
You can implement strong stickiness for you upstream services by using the Envoy Stateful Session filter. This filter instructs the gateway proxy to pick an upstream service instance that serves the request, encode its address, and to return this value as a header or cookie to the requesting client. If the header or cookie is used in subsequent requests, the gateway proxy forwards all traffic to the instance that served the inital request.
This feature is an Enterprise-only feature that requires a Gloo Gateway Enterprise license.
Before you begin
Follow the Get started guide to install Gloo Gateway, set up a gateway resource, and deploy the httpbin sample app.
Get the external address of the gateway and save it in an environment variable.
Choose between the following options to set up the stateful session filter:
Header-based session affinity
Set up header-based session affinity on your gateway proxy. When a request comes in, the proxy chooses an upstream service instance that serves the request, decodes the instance’s address to base64, and stores the base64-encoded value in a header. If the header is provided in subsequent requests, the gateway proxy forwards traffic to the same instance, thereby establishing session affinity.
Scale the httpbin app up to 2 instances.
kubectl scale deployment httpbin -n httpbin --replicas=2
Verify that another instance of the httpbin app is created and note the IP addresses of both httpbin instances. In the following example, you have an httpbin instance available at the
10.0.43.175
and10.0.38.52
IP addresses.kubectl get pods -n httpbin -o wide
Example output
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpbin-8d557795f-86hzg 3/3 Running 0 54m 10.0.43.175 ip-10-0-34-108.ec2.internal <none> <none> httpbin-8d557795f-h8ks9 3/3 Running 0 126m 10.0.38.52 ip-10-0-39-74.ec2.internal <none> <none>
Create an HttpListenerOption resource that enables header-based session affinity on your gateway proxy. In the following example, when a request reaches the proxy, the proxy chooses an upstream service instance to fulfill the request. The proxy encodes the IP address of the instance to base64 and returns it in the
x-session-id
header.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: HttpListenerOption metadata: name: session namespace: gloo-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http namespace: gloo-system options: statefulSession: headerBased: headerName: x-session-id EOF
Send a request to the httpbin app. Verify that you get back a 200 HTTP response code and that you see the base64-encoded value of the httpbin instance that served the inital request in the
x-session-id
header.Example output:
* Request completely sent off < HTTP/1.1 200 OK HTTP/1.1 200 OK ... < x-envoy-upstream-service-time: 0 x-envoy-upstream-service-time: 0 < x-session-id: MTAuMC4zOC41Mjo4MDgw x-session-id: MTAuMC4zOC41Mjo4MDgw < server: envoy server: envoy ...
Optional: Decode the base64-encoded value of the
x-session-id
header and ensure that this session ID points to one of IP addresses of the httpbin instances that you retrieved earlier.echo "MTAuMC4zOC41Mjo4MDgw" | base64 -D
Example output:
10.0.38.52:8080%
Send a few more requests to the httpbin app. This time, you include the session ID that was returned in your first request to direct all requests to the httpbin instance that served the inital request.
Get the logs of the httpbin instance that served the request and verify that all requests were served by the same instance.
kubectl logs <httpbin-pod> -n httpbin
Example log entry:
time="2025-03-05T18:57:18.446" status=200 method="GET" uri="/headers" size_bytes=367 duration_ms=0.05 user_agent="curl/8.7.1" client_ip=10.0.XX.XX:45776
Cookie-based session affinity
Set up cookie-based session affinity on your gateway proxy. When a request comes in, the proxy chooses an upstream service instance that serves the request, decodes the instance’s address to base64, and stores the base64-encoded value in a cookie. If the cookie is provided in subsequent requests, the gateway proxy forwards traffic to the same instance, thereby establishing session affinity.
Scale the httpbin app up to 2 instances.
kubectl scale deployment httpbin -n httpbin --replicas=2
Verify that another instance of the httpbin app is created and note the IP addresses of both httpbin instances. In the following example, you have an httpbin instance available at the
10.0.43.175
and10.0.38.52
IP addresses.kubectl get pods -n httpbin -o wide
Example output
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpbin-8d557795f-86hzg 3/3 Running 0 54m 10.0.43.175 ip-10-0-34-108.ec2.internal <none> <none> httpbin-8d557795f-h8ks9 3/3 Running 0 126m 10.0.38.52 ip-10-0-39-74.ec2.internal <none> <none>
Create an HttpListenerOption to set up cookie-based session affinity on your gateway proxy. In the following example, when a request reaches the proxy, the proxy chooses an upstream service instance to fulfill the request. The proxy encodes the IP address of the instance to base64 and returns it in a
statefulsessioncookie
cookie. The cookie expires after 60 seconds (TTL).kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: HttpListenerOption metadata: name: session namespace: gloo-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http options: statefulSession: cookieBased: cookie: name: statefulsessioncookie path: / ttl: 60s EOF
Send a request to the httpbin app and verify that you see the
statefulsessioncookie
cookie in theset-cookie
header of your response. The-c
option stores the cookie in a local file on your machine so that you can use it in subsequent requests.Example output:
HTTP/1.1 200 OK ... set-cookie: statefulsessioncookie="ChAxMC4wLjQzLjE3NTo4MDgwELerCQ=="; Max-Age=60; Path=/; HttpOnly server: envoy { "headers": { "Accept": [ "*/*" ], "Host": [ "www.example.com:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "f1341372-b7ab-4ec2-9d7a-48bf05265c0b" ] } }
Optional: Decode the base64-encoded value that was returned in the
statefulsessioncookie
cookie and ensure that this IP address matches one of IP addresses of the httpbin instances that you retrieved earlier.echo "ChAxMC4wLjQzLjE3NTo4MDgwELerCQ==" | base64 -D
Example output:
10.0.43.175:8080??
Send a few more requests to the httpbin app. This time, you include the cookie that you stored in the local file by using the
-b
option. Make sure to send these requests within the 60 second cookie validity period.Get the logs of the httpbin instance that served the initial request. Verify that all subsequent requests were also served by the same instance.
kubectl logs <httpbin-pod> -n httpbin
Example log entry:
time="2025-03-05T18:57:18.446" status=200 method="GET" uri="/headers" size_bytes=367 duration_ms=0.05 user_agent="curl/8.7.1" client_ip=10.0.XX.XX:45776
After the cookie reaches its TTL and expires, the proxy starts choosing a new upstream instance to serve the request.
Cleanup
You can optionally remove the resources that you created in this guide.
kubectl delete httplisteneroption session -n gloo-system
kubectl scale deployment httpbin -n httpbin --replicas=1