How can I use Sticky sessions in Traefik v2.3?
When I enable the below line in my docker compose file, my docker services (e.g. http://192.168.0.1:9086) don't work.
- "traefik.http.services.mynginximage2.loadBalancer.sticky.cookie=true"
Do you have any idea why a sticky session doesn't work?
And is it possible to make a session affinity by the labels of a service?
The following is my docker compose file:
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.web.address=:80"
- "--entrypoints.mynginximage2_ep.address=:8086"
ports:
- 80:80
- 9086:8086
- 8080:8080
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
image: "traefik/whoami"
deploy:
replicas: 2
networks:
- traefik-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.routers.whoami.rule=Host(`192.168.0.1`) || Host(`192.168.0.2`)"
#- "traefik.http.services.whoami.loadBalancer.sticky.cookie=true"
- "traefik.http.services.whoami-service.loadbalancer.server.port=80"
mynginximage2:
image: mynginximage2
deploy:
replicas: 2
networks:
- traefik-net
#ports:
# - 9080:8086
labels:
- "traefik.enable=true"
- "traefik.http.routers.mynginximage2.entrypoints=mynginximage2_ep"
- "traefik.http.routers.mynginximage2.rule=Host(`192.168.0.1`) || Host(`192.168.0.2`)"
#- "traefik.http.services.mynginximage2.loadBalancer.sticky.cookie=true"
- "traefik.http.services.mynginximage2-service.loadbalancer.server.port=8086"
networks:
traefik-net:
external: true
name: traefik-net
I found the issue why my Traefik routers don't work when I enable a sticky session feature.
The solution is that each service has a different cookie name. So, I added cookie names. For example:
version: "3.8"
services:
#...
whoami:
#...
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.routers.whoami.rule=Host(`192.168.0.1`) || Host(`192.168.0.2`)"
- "traefik.http.services.whoami-service.loadBalancer.sticky.cookie=true"
- "traefik.http.services.whoami-service.loadBalancer.sticky.cookie.name=whoami_cookie_name"
- "traefik.http.services.whoami-service.loadbalancer.server.port=80"
mynginximage2:
#...
labels:
- "traefik.enable=true"
- "traefik.http.routers.mynginximage2.entrypoints=mynginximage2_ep"
- "traefik.http.routers.mynginximage2.rule=Host(`192.168.0.1`) || Host(`192.168.0.2`)"
- "traefik.http.services.mynginximage2-service.loadBalancer.sticky.cookie=true"
- "traefik.http.services.mynginximage2-service.loadBalancer.sticky.cookie.name=mynginximage2_cookie_name"
- "traefik.http.services.mynginximage2-service.loadbalancer.server.port=8086"
#...
Related
I am trying to deploy Wordpress application on docker swarm stack, behind Traefik reverse proxy, I wanted to use Nginx for reverse proxying but as the the Wordpress is deployed with 2 replicas I am facing session time out issue, therefore I am trying the use Traefik instaed to configure sticky session later.
I have deployed the Traefik service successfully and can access the dashboard, but the Wordpress is not being proxied and it is not showing in the services list on the dashboard.
Traefik Dashboard Screenshot
Traefik Dashboard 2
Traefik Proxy yaml File:
version: '3.3'
services:
traefik:
image: traefik:v2.2
ports:
- 80:80
- 443:443
deploy:
placement:
constraints:
# Make the traefik service run only on the node with this label
# as the node with it has the volume for the certificates
- node.labels.traefik-public.traefik-public-certificates == true
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
- traefik.http.middlewares.admin-auth.basicauth.users=${USERNAME?Variable not set}:${HASHED_PASSWORD?Variable not set}
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
- traefik.http.routers.traefik-public-http.rule=Host(`${DOMAIN?Variable not set}`)
- traefik.http.routers.traefik-public-http.entrypoints=http
- traefik.http.routers.traefik-public-http.middlewares=https-redirect
- traefik.http.routers.traefik-public-https.rule=Host(`${DOMAIN?Variable not set}`)
- traefik.http.routers.traefik-public-https.entrypoints=https
- traefik.http.routers.traefik-public-https.tls=true
- traefik.http.routers.traefik-public-https.service=api#internal
- traefik.http.routers.traefik-public-https.tls.certresolver=le
- traefik.http.routers.traefik-public-https.middlewares=admin-auth
- traefik.http.services.traefik-public.loadbalancer.server.port=8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-public-certificates:/certificates
command:
- --providers.docker
- --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`)
- --providers.docker.exposedbydefault=false
- --providers.docker.swarmmode
- --entrypoints.http.address=:80
- --entrypoints.https.address=:443
- --certificatesresolvers.le.acme.email=${EMAIL?Variable not set}
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
- --certificatesresolvers.le.acme.tlschallenge=true
- --accesslog
- --log
- --api
networks:
- traefik-public
volumes:
traefik-public-certificates:
networks:
traefik-public:
external: true
Wordpress yaml File:
version: "3.4"
services:
db:
image: mariadb
secrets:
- db_user
- db_pass
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_pass
MYSQL_USER_FILE: /run/secrets/db_user
MYSQL_PASSWORD_FILE: /run/secrets/db_pass
MYSQL_DATABASE_NAME: wpdb
ports:
- 3306:3306
networks:
- backend
volumes:
- db-data:/var/lib/mysql
deploy:
replicas: 1
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 60s
wp:
image: wordpress
secrets:
- db_user
- db_pass
depends_on:
- db
labels:
- traefik.enable=true
- traefik.constraint-label=traefik-public
- traefik.docker.network=traefik-public
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
- traefik.http.routers.wp.rule=Host(`example.com`)
- traefik.http.routers.wp.entrypoints=http
- traefik.http.routers.wp.middlewares=https-redirect
- traefik.http.routers.wp-secured.rule=Host(`example.com`)
- traefik.http.routers.wp-secured.entrypoints=https
- traefik.http.routers.wp-secured.tls=true
- traefik.http.routers.wp-secured.tls.certresolver=le
- traefik.http.services.wp.loadbalancer.server.port=8080
environment:
WORDPRESS_DB_HOST: 192.168.20.30:3306 # node IP
WORDPRESS_DB_USER_FILE: /run/secrets/db_user
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_pass
WORDPRESS_DB_NAME: wpdb
networks:
- backend
- traefik-public
volumes:
- wp-data:/var/www/html
deploy:
replicas: 2
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 60s
networks:
backend:
external: false
traefik-public:
external: true
volumes:
wp-data:
db-data:
secrets:
db_user:
file: ./db_user.txt
db_pass:
file: ./db_pass.txt
```
I'm trying my best to get Traefik dashboard available through http://gateway.localhost/dashboard/, but I'm always getting a 404 response* from Traefik. Can s.o. please review my stack file and tell me, why it's not working?
I tried it on my server with a valid domain, but it's either working there or on localhost with Docker Desktop in Swarm mode. The WhoAmI service can be reached through http://localhost which is correct.
docker stack deploy -c traefik.yml traefik
*404 is returned for these routes too: http://gateway.localhost, http://gateway.localhost/dashboard
traefik.yml:
version: '3'
services:
reverse-proxy:
image: traefik:v2.5
command:
- "--providers.docker.swarmmode=true"
- "--providers.docker.exposedByDefault=false"
- "--api.dashboard=true"
- "--entrypoints.web.address=:80"
# Logging
- "--accesslog"
- "--log.level=INFO"
ports:
- "80:80"
deploy:
labels:
#Because Swarm API does not support automatic way
- "traefik.http.services.reverse-proxy.loadbalancer.server.port=80"
#Dashboard
- "traefik.http.routers.dashboard.rule=Host(`gateway.localhost`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.dashboard.service=api#internal"
- "traefik.http.routers.dashboard.entrypoints=web"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
placement:
constraints:
- node.role == manager
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
whoami:
image: traefik/whoami
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
You need to enable traefik for the container with the traefik.enable=true label:
version: '3'
services:
reverse-proxy:
image: traefik:v2.5
command:
- "--providers.docker.swarmmode=true"
- "--providers.docker.exposedByDefault=false"
- "--api.dashboard=true"
- "--entrypoints.web.address=:80"
# Logging
- "--accesslog"
- "--log.level=INFO"
ports:
- "80:80"
deploy:
labels:
######## add the following label to enable traefik #######
- "traefik.enable=true"
#Because Swarm API does not support automatic way
- "traefik.http.services.reverse-proxy.loadbalancer.server.port=80"
#Dashboard
- "traefik.http.routers.dashboard.rule=Host(`gateway.localhost`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.dashboard.service=api#internal"
- "traefik.http.routers.dashboard.entrypoints=web"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
placement:
constraints:
- node.role == manager
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
whoami:
image: traefik/whoami
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
version: '3.2'
services:
traefik:
image: "traefik:latest"
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --providers.docker.swarmMode=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=public
- --api
- --log.level=ERROR
ports:
- "80:80"
- "443:443"
networks:
- public
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
agent:
image: portainer/agent
environment:
# REQUIRED: Should be equal to the service name prefixed by "tasks." when
# deployed inside an overlay network
AGENT_CLUSTER_ADDR: tasks.agent
# AGENT_PORT: 9001
# LOG_LEVEL: debug
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- agent_network
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
portainer:
image: portainer/portainer-ce:2.0.0
command: -H tcp://tasks.agent:9001 --tlsskipverify
volumes:
- data:/data
networks:
- public
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.yourdomain.com`)"
- "traefik.http.routers.portainer.entrypoints=web"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
- "traefik.http.routers.portainer.service=portainer"
# Edge
- "traefik.http.routers.edge.rule=Host(`edge.yourdomain.com`)"
- "traefik.http.routers.edge.entrypoints=web"
- "traefik.http.services.edge.loadbalancer.server.port=8000"
- "traefik.http.routers.edge.service=edge"
networks:
public:
external: true
agent_network:
external: true
volumes:
We can see that "portainer" is in both public and agent_network overlay networks. And it has two IP addresses, 10.0.38.7 and 10.0.39.7.
traefik is only in public network, it has IP address 10.0.38.6.
The problem is, from traefik web UI, it refers "portainer" as 10.0.39.7 instead of 10.0.38.7. So that it fails to work.
Any solution to this?
I'm facing a problem on my production server with a container that contains the latest version of the image but when I'm executing it, the content is not the last one.
To update docker images, I execute a little script with theses commands
docker-compose pull
docker-compose up -d --remove-orphans
docker-compose prune -fa
Of course, the image used in the docker service is with the latest tag
image: registry.gitlab.com/xxxxx/api:latest
Here is two screenshots with the container and the image content to see the differences
Here is my docker-compose.yml
version: '3.3'
services:
traefik:
image: "traefik:v2.4"
container_name: "traefik"
command:
- "--api"
- "--providers.docker"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.address=:80"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=com#xxxxx.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--pilot.token=xxxxx"
ports:
- 80:80
- 443:443
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
labels:
# dashboard
- "traefik.http.routers.monitor.service=api#internal"
- "traefik.http.routers.monitor.rule=Host(`monitor.xxxxx.com`)"
- "traefik.http.routers.monitor.entrypoints=websecure"
- "traefik.http.routers.monitor.tls.certresolver=myresolver"
# global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
api:
image: registry.gitlab.com/xxxxx/api:latest
ports:
- 4200:8080
volumes:
- api-data:/app
depends_on:
- db
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.xxxxx.com`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=myresolver"
front:
image: registry.gitlab.com/xxxxx/front:latest
ports:
- 3000:3000
labels:
- "traefik.enable=true"
- "traefik.http.routers.front.rule=Host(`dev.xxxxx.com`)"
- "traefik.http.routers.front.entrypoints=websecure"
- "traefik.http.routers.front.tls.certresolver=myresolver"
panel:
image: registry.gitlab.com/xxxxx/panel:latest
ports:
- 3001:3000
depends_on:
- api
labels:
- "traefik.enable=true"
- "traefik.http.routers.panel.rule=Host(`admin.xxxxx.com`)"
- "traefik.http.routers.panel.entrypoints=websecure"
- "traefik.http.routers.panel.tls.certresolver=myresolver"
coming-soon:
image: registry.gitlab.com/xxxxx/coming-soon:latest
ports:
- 3002:3000
labels:
- "traefik.enable=true"
- "traefik.http.routers.coming-soon.rule=Host(`xxxxx.com`) || Host(`www.xxxxx.com`)"
- "traefik.http.routers.coming-soon.entrypoints=websecure"
- "traefik.http.routers.coming-soon.tls.certresolver=myresolver"
db:
image: postgres
ports:
- 5432:5432
volumes:
- db-data:/var/lib/postgresql/data/
env_file:
- .env
restart: always
adminer:
image: dpage/pgadmin4
ports:
- 5000:80
volumes:
- adminer-data:/root/.pgadmin
env_file:
- .env
depends_on:
- db
labels:
- "traefik.enable=true"
- "traefik.http.routers.adminer.rule=Host(`adminer.xxxxx.com`)"
- "traefik.http.routers.adminer.entrypoints=websecure"
- "traefik.http.routers.adminer.tls.certresolver=myresolver"
gitlab-runner:
image: gitlab/gitlab-runner:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
mode: replicated
replicas: 2
update_config:
parallelism: 4
delay: 30s
volumes:
db-data:
api-data:
adminer-data:
I am trying to configure traefik to connect between my 3 docker containers.
I tried with this configuration but I got net::ERR_NAME_NOT_RESOLVED on my browser console.
searchservice:
hostname: searchservice
image: searchservice:0.0.3-SNAPSHOT
container_name: searchservice
networks:
- es-network
#ipv4_address: 172.21.0.12
ports:
- 8070:8080
restart: always
depends_on:
- elasticsearch
- reverseproxy
labels:
- "traefik.frontend.rule=PathPrefix:/searchservice,Host:localhost"
- "traefik.port: 8070"
- "traefik.enable=true"
subscriber-service:
hostname: subscriber-service
image: subscriberservice:0.0.4-SNAPSHOT
container_name: subscriber-service
networks:
- es-network
#ipv4_address: 172.21.0.13
ports:
- 8090:8090
restart: always
depends_on:
- mongo1
- mongo2
- reverseproxy
labels:
- "traefik.frontend.rule=PathPrefix:/api,Host:localhost"
- "traefik.port: 8090"
- "traefik.enable=true"
searchappfront:
hostname: searchappfront
image: frontservice:latest
container_name: searchappfront
networks:
- es-network
ports:
- 80:80
restart: always
depends_on:
- subscriber-service
- searchservice
- reverseproxy
labels:
- "traefik.frontend.rule=PathPrefix:/"
- "traefik.enable=true"
- "traefik.port=80"
# - "traefik.frontend.rule=Host:localhost"
reverseproxy:
image: traefik:v2.1
command:
- '--providers.docker=true'
- '--entryPoints.web.address=:80'
- '--providers.providersThrottleDuration=2s'
- '--providers.docker.watch=true'
- '--providers.docker.defaultRule=Host("local.me")'
- '--accessLog.bufferingSize=0'
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
#ports:
# - '80:80'
# - '8080:8080'
The searchappfront is an angular application where the http endPoints have this pattern
http://subscriber-service:8090/
http://searchservice:8070/
if I use localhost instead of hostnames, requests work fine but I need to deploy these containers in a cloud instance.
You are using traefik 2, but your annotation is for traefik 1. This is not going to work.