Introduction
This article explains how to implement cookie-based session affinity using Consul’s ServiceResolver
with a Maglev load balancer and cookie hash policies. This ensures that HTTP clients consistently route to the same backend instance, preventing issues such as repeated login prompts or session loss when requests are distributed across different replicas.
Expected Outcome
Once completed, your HTTP clients will:
- Receive a
Set-Cookie
from Consul’s service mesh on the first request. - Include this cookie in subsequent requests to ensure they are consistently routed to the same backend instance.
- Avoid issues caused by random distribution across backend replicas.
Prerequisites
- Consul service mesh with upstream connectivity
- Consul
ServiceResolver
config entries -
curl
command installed
Use Case
You have applications behind the Consul API Gateway that require session stickiness—for example, a login-based application where routing the same user to different backend instances breaks the session.
Since currently, Consul API Gateway does not enforce cookie-based session affinity. This can be achieved using Consul’s ServiceResolver
with a Maglev load balancer and cookie hash policies
Procedure
Step 1: Create the ServiceResolver
Config Entry
Create the following configuration to tell Consul to use Maglev load balancing and hash requests based on the cookie application-cookie
:
Kind = "service-resolver"
Name = "hello-app"
LoadBalancer = {
Policy = "maglev"
HashPolicies = [
{
Field = "cookie"
FieldValue = "application-cookie"
CookieConfig = {
TTL = "60s"
}
}
]
}
Apply it with:
consul config write service-resolver.hcl
Step 2: Verify the Config is Active
Run the following to confirm Consul has registered the configuration:
consul config entries list
consul config entries read -kind service-resolver -name hello-app
Additional Evidence from Downstream Config Dump
Inspect the Envoy clusters section from /config_dump
(on admin port, typically localhost:19000/config_dump
) from the downstream.
- After applying the Maglev config entry, it shows:
"lb_policy": "MAGLEV"
This confirms that your upstream load balancing policy was updated from round robin to Maglev.
Also note how the dynamic_route_configs
from the /config_dump
reflects that the route now uses the cookie for hashing:
"dynamic_route_configs": [ { "route_config": { "virtual_hosts": [ { "routes": [ { "match": { "path": "/" }, "route": { "cluster": "frontend.default.dc1.internal.1b6139e0-0cc1-d519-8702-f84510b55fcd.consul", "hash_policy": [ { "cookie": { "name": "application-cookie", "ttl": "60s" } } ] } } ] } ] } } ]
Step 3: Make an Initial HTTP Request to Get the Cookie
Run this curl from downstream and capture the Set-Cookie
:
curl -vvv -s $(kubectl get svc api-gateway -n consul -o jsonpath='{.status.loadBalancer.ingress[0].ip}') -i
Sample output:
< HTTP/1.1 200 OK
< set-cookie: application-cookie="f13a7f447b77ee49"; Max-Age=60; HttpOnly
{
"ip_addresses": ["10.42.2.16"],
"body": "Hello World",
"code": 200
}
Step 4: Validate Session Stickiness by Reusing the Cookie
Use this loop to see that your requests consistently hit the same backend:
for x in `seq 5`
do
curl -s -b application-cookie="f13a7f447b77ee49" $(kubectl get svc api-gateway -n consul -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
done
Sample output:
{
"ip_addresses": ["10.42.2.16"], "body": "Hello World"
}
This demonstrates that the session affinity is correctly enforced.