3

I have a dockerized node.js app that uses socket.io

Via docker compose I run 2 replicas for the app on two diffrent containers on the same server. However the requests that come to the servers is distributed in a round robin fashion.

Is there a way that I can use to achieve sticky sessions ?

my docker-compose.yml looks like below

version: '3'

services:
 app:
   ports:
     - "3001:3001"
   image: image
   deploy:
     replicas: 2

and I use the docker stack deploy to run the two replicas for the app

Siyu
  • 11,187
  • 4
  • 43
  • 55
Ahmed Ghazy
  • 81
  • 2
  • 7

2 Answers2

5

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/;
        }
    }
}
Chen A.
  • 10,140
  • 3
  • 42
  • 61
0

I think what you are looking for is this document describing different approaches to session persistence while using Docker Swarm.

In particular you can configure Cookie or IP Hashing based sticky session.

According the online documentation it looks like you need to add following labels to your config:

labels:
   - "com.docker.lb.hosts=demo.local"
   - "com.docker.lb.sticky_session_cookie=session" 
   - "com.docker.lb.port=3001"
dongi
  • 378
  • 1
  • 3
  • I tried adding these lines and also running the service as mentioned in the document but still nothing works. The difference I guess is that in the example the service is an nginx where in my case it is node.js app – Ahmed Ghazy Jan 28 '19 at 15:41
  • For this you need to use Docker Swarm and enable it's [Layer 7 Routing](https://docs.docker.com/ee/ucp/interlock/deploy/). Once you've got it in place it should work. – dongi Jan 28 '19 at 17:14
  • 2
    The documentation is for Docker EE; anyone know if Docker CE is out of luck? – Foon May 15 '20 at 18:22
  • Yes this approach only works for EE. It won’t work for CE. – Andy Madge Feb 20 '21 at 23:02