Introduction
Assume that you have already setup a Docker Swarm cluster, and now you can add a main Traefik (CE – Community Edition) as the Load Balancer/Proxy to:
– Expose specific services or applications based on their domain or DNS name or sub-domain.
– Automatic & Dynamic Routing (within container micro-services).
– Auto Discovery container services based on Docker Labels.
– …etc.
Overview:
- In this lab, we will have more than 3 nodes, 3 nodes for managers and 2 nodes for workers. Note: Traefik needs to run on manager nodes because it will be able to get “/var/run/docker.sock” otherwise you need to configure docker swarm manager to run TCP mode instead.
- In case, we will deploy Traefik (CE) on all manager nodes and configure/expose HTTPs/443 with self-signed certificate.
- We will use basic authentication in order to access Traefik Dashboard.
- For testing, we will deploy an application name “Whoami” on 2 worker nodes, let says 2 whoami containers running each worker nodes.
Prerequisites
- LAB Specs
Role | Hostname | IP | OS | AWS EC2 |
Swarm Manager-01 | swmgr-01 | 10.0.0.109 | Ubuntu 20.04 | t2.micro |
Swarm Manager-02 | swmgr-02 | 10.0.0.74 | Ubuntu 20.04 | t2.micro |
Swarm Manager-03 | swmgr-03 | 10.0.0.218 | Ubuntu 20.04 | t2.micro |
Swarm Worker-01 | swwkr-01 | 10.0.0.247 | Ubuntu 20.04 | t2.micro |
Swarm Worker-02 | swwkr-02 | 10.0.0.176 | Ubuntu 20.04 | t2.micro |
- Generate self-signed certificate if you do not have your own public certificate
mkdir -p /srv/traefik/certs
cd /srv/traefik/certs/
# Make "openssl" installed or if not yet, run command:
sudo apt install openssl
# Create "Self-Signed SSL Certificate" with command:
openssl req -newkey rsa:4096 \
-x509 \
-sha256 \
-days 3560 \
-nodes \
-out server.crt \
-keyout server.key
# "-newkey rsa:4096": Creates a new certificate request and 4096 bit RSA key. The default one is 2048 bits.
# "-x509": Creates a X.509 Certificate.
# "-sha256": Use 265-bit SHA (Secure Hash Algorithm).
# "-days 3650": The number of days to certify the certificate for 3650 is ten years. you can set days as your prefer.
# "-nodes": Create a key without a passphrase.
# "-out server.crt": Specific the filename to write the newly create certificate.
# "-keyout server.key": Specific the filename to write the newly created private key.
chmod 400 *.{key,crt}
chmod 600 ../certs
- Create docker secret to store those self-signed certificates (.key, .pem) on any manager node
docker secret create server-key /srv/traefik/certs/server.key
docker secret create server-crt /srv/traefik/certs/server.crt
docker secret ls
- Create docker overlay network for “Traefik” as Load Balancer and name “traefik-net”
docker network create --attachable --driver overlay traefik-net
- Generate a hash-password for Traefik Dashboard basic authentication
# echo $(htpasswd -nb <user> <secure_password>) | sed -e s/\\$/\\$\\$/g
echo $(htpasswd -nb tfadmin changeme) | sed -e s/\\$/\\$\\$/g
--> The result should be similar: tfadmin:$$apr1$$dQnzkAzD$$HWO8dGh/dy5Ocy0KvZh/k.
Deploy Traefik as Load Balancer
- Create main Traefik Configuration with YAML file
cd /srv/traefik/
cat <<'EOF' | sudo tee traefik.yml
## STATIC CONFIG (restart traefik to update)
# shows you a log msg if a newer image tag can be used
global:
checkNewVersion: true
# log default is ERROR, but WARN is more helpful
log:
level: WARN
# level: INFO
# enable dashboard on 8080 with NO AUTH
api:
insecure: true
dashboard: true
# enable ping so the `traefik healthcheck` works
ping: {}
# auto-proxy containers if they have proper labels
# and also use this file for dynamic config (tls)
providers:
docker:
swarmMode: true
exposedByDefault: false
watch: true
file:
fileName: /etc/traefik/traefik.yml
watch: true
# listen on 80/443, and redirect all 80 to 443 via 301
entryPoints:
web:
address: :80
# comment out these lins if you don't want to redirect everything
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: :443
## DYNAMIC CONFIG
tls:
certificates:
- certFile: /certs/server.crt
keyFile: /certs/server.key
options:
default:
sniStrict: true
EOF
- Create Docker Compose file to deploy Traefik
cd /srv/traefik/
cat <<'EOF' | sudo tee docker-compose.yml
version: "3.7"
networks:
traefik-net:
external: true
configs:
traefik_yml:
file: ./traefik.yml
secrets:
server-key:
external: true
server-crt:
external: true
services:
traefik:
image: traefik:v2.4.8
deploy:
mode: global
restart_policy:
condition: on-failure
update_config:
parallelism: 1
delay: 10s
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard.tls=true"
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik-dashboard.lab.local`)"
- "traefik.http.routers.traefik-dashboard.service=api@internal"
- "traefik.http.routers.traefik-dashboard.middlewares=tfdash-auth"
- "traefik.http.middlewares.tfdash-auth.basicauth.users=tfadmin:$$apr1$$dQnzkAzD$$HWO8dGh/dy5Ocy0KvZh/k." # generate your own credential echo $(htpasswd -nb <user> <secure_password>) | sed -e s/\\$/\\$\\$/g
# Dummy service for Swarm port detection. The port can be any valid integer value.
- "traefik.http.services.traefik-dashboard.loadbalancer.server.port=9999"
healthcheck:
test:
- CMD
- traefik
- healthcheck
interval: 10s
timeout: 5s
retries: 3
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
networks:
- traefik-net
configs:
- source: traefik_yml
target: /etc/traefik/traefik.yml
mode: 0440
secrets:
- source: server-key
target: /certs/server.key
mode: 0440
- source: server-crt
target: /certs/server.crt
mode: 0440
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
EOF
- Start deploy Traefik stack with stack named “traefik”
cd /srv/traefik/
docker stack deploy -c docker-compose.yml traefik
- Verify the deployment
docker stack ls
docker service ls
docker service logs -ft traefik_traefik
docker service ps traefik_traefik
Testing
To test, you can set your host file or DNS name point to any of manager node(s). In case we use AWS EC2 then there are 3 Public IPv4 addresses (temporarily):
– 54.179.128.50 –> swmgr-01
– 13.212.142.91 –> swmgr-02
– 54.255.152.199 –> swmgr-03
To access dashboard, we can set host file named “traefik-dashboard.lab.local” point to any above manager public IPv4 with basic authentication:

Deploy Whoami application as the following:
mkdir -p /srv/whoami
cd /srv/whoami/
cat <<'EOF' | sudo tee docker-compose.yml
version: '3.7'
networks:
traefik-net:
external: true
services:
whoami:
image: containous/whoami:latest
networks:
- traefik-net
deploy:
mode: replicated
replicas: 4
restart_policy:
condition: on-failure
update_config:
parallelism: 1
delay: 10s
placement:
constraints:
- node.role == worker
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.lab.local`)"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
EOF
- To deploy Whoami Application and replicates as 4 containers on worker nodes, run the command:
cd /srv/whoami/
docker stack deploy -c docker-compose.yml whoami
- To verify Whoami application deployment
docker stack ls
docker service ls
docker service ps whoami_whoami


- Now if we shutdown, swwkr-02, Whoami containers will startup all on swwrk-01 without interruption.

- Now if we shutdown swmgr-01, Traefik Load balancer service will be still running. But note we need to re-set host file address again by pointing to any available manager nodes.


Thanks!