As far as I understand, there are 3 possible variations to implement session affinity on Docker or Docker Swarm.
1. Add labels to establish a sticky session, which is the very simple and official way if you are using Docker Enterprise Edition.
labels:
- "com.docker.lb.hosts=example.com"
- "com.docker.lb.sticky_session_cookie=session"
- "com.docker.lb.port=3001"
You need to use one of the following two methods unless you bought the license to use Docker EE.
2. Use Traefik load balancer. Let's assume deploying a service named app; containers are deployed in 192.168.0.1 and 192.168.0.2 which are the nodes connected in Docker Swarm.
version: "3.8"
services:
traefik:
image: traefik:v2.3
deploy:
mode: global
networks:
- traefik-net
command:
- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.app.address=:80"
ports:
- 3001:80
- 8080:8080
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
app:
image: nginx
deploy:
replicas: 2
networks:
- traefik-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.entrypoints=app"
- "traefik.http.routers.app.rule=Host(`192.168.0.1`) || Host(`192.168.0.2`)"
- "traefik.http.services.app-service.loadBalancer.sticky.cookie=true"
- "traefik.http.services.app-service.loadBalancer.sticky.cookie.name=app_cookie_name"
- "traefik.http.services.app-service.loadbalancer.server.port=80"
networks:
traefik-net:
external: true
name: traefik-net
3. Use Nginx reverse proxy. Let's assume containers will deploy in 192.168.0.1 and 192.168.0.2 which are the nodes connected in Docker Swarm.
In order to bypass the routing mesh, you need to deploy two services (app1, app2) with one replica because Docker Swarm's default load balance method is round-robin.
version: "3.8"
services:
app1:
ports:
- "3001:3001"
image: image
deploy:
replicas: 1
app2:
ports:
- "3002:3001"
image: image
deploy:
replicas: 1
Nginx configuration:
You need to register each way to reach out to a container because Docker Swarm uses the routing mesh (round-robin load balancer).
http {
upstream example {
ip_hash;
server 192.168.0.1:3001;
server 192.168.0.1:3002;
server 192.168.0.2:3001;
server 192.168.0.2:3002;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://example/;
}
}
}