Traefik détecte automatiquement vos conteneurs Docker et crée les routes correspondantes sans fichier de configuration à maintenir. Vous définissez le routage directement via des labels sur vos conteneurs : Traefik lit ces labels, génère la configuration et l’applique en temps réel.
Ce guide vous montre comment configurer le provider Docker, écrire les labels de routage, gérer les réseaux, et déployer des applications complètes avec Docker Compose. À la fin, vous saurez exposer n’importe quel conteneur en quelques secondes.
Comment fonctionne le provider Docker
Section intitulée « Comment fonctionne le provider Docker »Découverte automatique
Section intitulée « Découverte automatique »Quand le provider Docker est activé, Traefik :
- Se connecte au daemon Docker via le socket Unix
- Surveille les événements (création, suppression, modification de conteneurs)
- Lit les labels de chaque conteneur
- Génère la configuration de routage correspondante
- Applique immédiatement les changements (hot-reload)
Communication via le socket Docker
Section intitulée « Communication via le socket Docker »Traefik communique avec Docker via le socket Unix (/var/run/docker.sock). Ce socket donne accès à toute l’API Docker, ce qui pose un risque de sécurité.
Analogie : Le socket Docker, c’est comme donner les clés de tout l’immeuble. En production, on préfère donner uniquement les clés des pièces nécessaires (via un proxy).
Labels comme configuration dynamique
Section intitulée « Labels comme configuration dynamique »Les labels Docker sont des métadonnées clé-valeur attachées aux conteneurs. Traefik les utilise pour configurer :
- Les routers : règles de routage (Host, Path…)
- Les services : port du conteneur, load balancing
- Les middlewares : authentification, headers, rate limiting
Configuration du provider Docker
Section intitulée « Configuration du provider Docker »Configuration minimale
Section intitulée « Configuration minimale »Dans votre fichier traefik.yaml (configuration statique) :
providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false| Option | Description | Recommandation |
|---|---|---|
endpoint | Chemin du socket Docker | Toujours unix:///var/run/docker.sock sur Linux |
exposedByDefault | Expose automatiquement tous les conteneurs | false (sécurité) |
Options avancées
Section intitulée « Options avancées »providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: traefik-public # Réseau par défaut watch: true # Surveiller les changements defaultRule: "Host(`{{ normalize .Name }}.example.com`)" # Règle par défaut constraints: "Label(`traefik.zone`, `public`)" # Filtrer les conteneurs| Option | Description |
|---|---|
network | Réseau Docker à utiliser pour la communication |
watch | Surveiller les événements Docker en temps réel |
defaultRule | Règle de routage par défaut (utilise les templates Go) |
constraints | Expression pour filtrer les conteneurs à considérer |
Exposer un conteneur simple
Section intitulée « Exposer un conteneur simple »-
Créer le fichier docker-compose.yml
docker-compose.yml services:traefik:image: traefik:v3.6container_name: traefikrestart: unless-stoppedcommand:- "--api.dashboard=true"- "--api.insecure=true"- "--providers.docker=true"- "--providers.docker.exposedbydefault=false"- "--entrypoints.web.address=:80"ports:- "80:80"- "8080:8080"volumes:- /var/run/docker.sock:/var/run/docker.sock:ronetworks:- traefik-publicwhoami:image: traefik/whoamicontainer_name: whoamilabels:- "traefik.enable=true"- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"- "traefik.http.routers.whoami.entrypoints=web"networks:- traefik-publicnetworks:traefik-public:name: traefik-public -
Lancer les conteneurs
Fenêtre de terminal docker compose up -d# Vérifier le statutdocker compose psRésultat attendu :
NAME IMAGE STATUS PORTStraefik traefik:v3.6 running 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcpwhoami traefik/whoami running -
Tester le routage
Fenêtre de terminal # Tester avec le header Hostcurl -H "Host: whoami.localhost" http://localhostRésultat attendu :
Hostname: whoamiIP: 172.19.0.3RemoteAddr: 172.19.0.2:56842GET / HTTP/1.1Host: whoami.localhostUser-Agent: curl/8.5.0Accept: */*Accept-Encoding: gzipX-Forwarded-For: 172.19.0.1X-Forwarded-Host: whoami.localhostX-Forwarded-Port: 80X-Forwarded-Proto: httpX-Forwarded-Server: traefikX-Real-Ip: 172.19.0.1
Référence des labels Traefik
Section intitulée « Référence des labels Traefik »Labels de base
Section intitulée « Labels de base »| Label | Description | Exemple |
|---|---|---|
traefik.enable | Activer l’exposition du conteneur | true ou false |
traefik.http.routers.<n>.rule | Règle de routage HTTP | Host('app.example.com') |
traefik.http.routers.<n>.entrypoints | Points d’entrée à utiliser | web,websecure |
traefik.http.routers.<n>.priority | Priorité du router (plus élevé = prioritaire) | 100 |
traefik.http.services.<n>.loadbalancer.server.port | Port du conteneur | 8080 |
Note : Remplacez <n> par le nom de votre router/service (ex: myapp, api, frontend).
Labels TLS
Section intitulée « Labels TLS »labels: # Activer TLS - "traefik.http.routers.myapp.tls=true"
# Utiliser un certificat resolver (Let's Encrypt) - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
# Domaines pour le certificat - "traefik.http.routers.myapp.tls.domains[0].main=example.com" - "traefik.http.routers.myapp.tls.domains[0].sans=www.example.com,api.example.com"Labels middlewares
Section intitulée « Labels middlewares »labels: # Attacher un ou plusieurs middlewares - "traefik.http.routers.myapp.middlewares=auth,compress,headers"
# Définir un middleware BasicAuth - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xxx"
# Définir un middleware Headers - "traefik.http.middlewares.headers.headers.stsSeconds=31536000" - "traefik.http.middlewares.headers.headers.contentTypeNosniff=true"
# Définir un RateLimit - "traefik.http.middlewares.ratelimit.ratelimit.average=100" - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"Labels TCP/UDP
Section intitulée « Labels TCP/UDP »Pour les services TCP ou UDP (bases de données, DNS…) :
labels: - "traefik.tcp.routers.mysql.rule=HostSNI(`*`)" - "traefik.tcp.routers.mysql.entrypoints=mysql" - "traefik.tcp.services.mysql.loadbalancer.server.port=3306"Réseaux Docker
Section intitulée « Réseaux Docker »Pourquoi utiliser un réseau dédié
Section intitulée « Pourquoi utiliser un réseau dédié »Par défaut, Docker crée un réseau bridge pour chaque projet Compose. Problème : Traefik ne peut pas atteindre les conteneurs d’autres projets.
Solution : Créer un réseau Docker externe partagé entre Traefik et tous les services à exposer.
┌─────────────────────────────────────────────────────────────────────────┐│ Réseau traefik-public ││ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ │ Traefik │ │ App A │ │ App B │ │ App C │ ││ │ │──│──────────│──│──────────│──│──────────│ ││ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │└─────────────────────────────────────────────────────────────────────────┘Configuration réseau
Section intitulée « Configuration réseau »-
Créer le réseau externe :
Fenêtre de terminal docker network create traefik-public -
Référencer le réseau dans docker-compose.yml :
docker-compose.yml services:myapp:image: nginxnetworks:- traefik-public- internal # Réseau interne pour base de donnéesnetworks:traefik-public:external: trueinternal:driver: bridge
Multi-réseaux
Section intitulée « Multi-réseaux »Un conteneur peut appartenir à plusieurs réseaux. Utilisez cette technique pour séparer :
- traefik-public : communication avec Traefik
- internal : communication entre services (base de données, cache)
services: wordpress: image: wordpress networks: - traefik-public # Accessible par Traefik - backend # Accès à MySQL labels: - "traefik.http.routers.wp.rule=Host(`blog.example.com`)" - "traefik.docker.network=traefik-public" # Préciser le réseau Traefik
mysql: image: mysql:8 networks: - backend # PAS sur traefik-public = pas accessible depuis InternetExemples pratiques
Section intitulée « Exemples pratiques »Application web simple (NGINX)
Section intitulée « Application web simple (NGINX) »services: nginx: image: nginx:alpine container_name: web volumes: - ./html:/usr/share/nginx/html:ro labels: - "traefik.enable=true" - "traefik.http.routers.web.rule=Host(`www.example.com`)" - "traefik.http.routers.web.entrypoints=websecure" - "traefik.http.routers.web.tls.certresolver=letsencrypt" networks: - traefik-public
networks: traefik-public: external: trueStack WordPress + MySQL
Section intitulée « Stack WordPress + MySQL »services: wordpress: image: wordpress:6 container_name: wordpress environment: WORDPRESS_DB_HOST: mysql WORDPRESS_DB_NAME: wordpress WORDPRESS_DB_USER: wp_user WORDPRESS_DB_PASSWORD: ${WP_DB_PASSWORD} volumes: - wordpress_data:/var/www/html labels: - "traefik.enable=true" - "traefik.http.routers.wordpress.rule=Host(`blog.example.com`)" - "traefik.http.routers.wordpress.entrypoints=websecure" - "traefik.http.routers.wordpress.tls.certresolver=letsencrypt" - "traefik.docker.network=traefik-public" networks: - traefik-public - backend
mysql: image: mysql:8 container_name: wordpress-db environment: MYSQL_DATABASE: wordpress MYSQL_USER: wp_user MYSQL_PASSWORD: ${WP_DB_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} volumes: - mysql_data:/var/lib/mysql networks: - backend # Pas exposé sur Internet
networks: traefik-public: external: true backend: driver: bridge
volumes: wordpress_data: mysql_data:API avec plusieurs réplicas
Section intitulée « API avec plusieurs réplicas »services: api: image: myapi:latest deploy: replicas: 3 labels: - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`api.example.com`)" - "traefik.http.routers.api.entrypoints=websecure" - "traefik.http.routers.api.tls.certresolver=letsencrypt" - "traefik.http.services.api.loadbalancer.server.port=3000" # Healthcheck pour le load balancing - "traefik.http.services.api.loadbalancer.healthcheck.path=/health" - "traefik.http.services.api.loadbalancer.healthcheck.interval=10s" networks: - traefik-publicApplication multi-services (frontend + API)
Section intitulée « Application multi-services (frontend + API) »services: frontend: image: myfrontend:latest labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`app.example.com`)" - "traefik.http.routers.frontend.entrypoints=websecure" - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" - "traefik.http.services.frontend.loadbalancer.server.port=80" networks: - traefik-public
api: image: myapi:latest labels: - "traefik.enable=true" # Même domaine, path différent - "traefik.http.routers.api.rule=Host(`app.example.com`) && PathPrefix(`/api`)" - "traefik.http.routers.api.entrypoints=websecure" - "traefik.http.routers.api.tls.certresolver=letsencrypt" - "traefik.http.services.api.loadbalancer.server.port=3000" # Middleware pour supprimer le préfixe /api - "traefik.http.routers.api.middlewares=api-stripprefix" - "traefik.http.middlewares.api-stripprefix.stripprefix.prefixes=/api" networks: - traefik-publicDocker Swarm
Section intitulée « Docker Swarm »Différences avec Docker standalone
Section intitulée « Différences avec Docker standalone »| Aspect | Docker standalone | Docker Swarm |
|---|---|---|
| Provider | docker | swarm |
| Unité | Conteneur | Service |
| Labels | Sur le conteneur | Dans deploy.labels |
| Réseau | Bridge ou overlay | Overlay obligatoire |
| Scaling | docker compose up --scale | docker service scale |
Configuration provider Swarm
Section intitulée « Configuration provider Swarm »providers: swarm: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: traefik-public watch: trueLabels Swarm spécifiques
Section intitulée « Labels Swarm spécifiques »En Swarm, les labels doivent être dans la section deploy.labels :
services: myapp: image: myapp:latest deploy: replicas: 3 labels: - "traefik.enable=true" - "traefik.http.routers.myapp.rule=Host(`app.example.com`)" - "traefik.http.services.myapp.loadbalancer.server.port=8080" networks: - traefik-publicDéploiement en mode Swarm
Section intitulée « Déploiement en mode Swarm »# Initialiser Swarm (si pas fait)docker swarm init
# Créer le réseau overlaydocker network create --driver=overlay --attachable traefik-public
# Déployer Traefik en mode globaldocker stack deploy -c traefik-stack.yml traefik
# Déployer l'applicationdocker stack deploy -c myapp-stack.yml myappGestion du socket Docker
Section intitulée « Gestion du socket Docker »Exposition directe (développement)
Section intitulée « Exposition directe (développement) »En développement, monter le socket directement est acceptable :
volumes: - /var/run/docker.sock:/var/run/docker.sock:roLe :ro (read-only) est une protection minimale, mais Traefik peut toujours lire toutes les informations Docker.
Socket proxy (production)
Section intitulée « Socket proxy (production) »En production, utilisez docker-socket-proxy pour limiter les endpoints API accessibles :
services: socket-proxy: image: tecnativa/docker-socket-proxy container_name: socket-proxy restart: unless-stopped environment: # Endpoints autorisés (lecture seule) CONTAINERS: 1 SERVICES: 1 NETWORKS: 1 TASKS: 1 # Endpoints bloqués BUILD: 0 COMMIT: 0 CONFIGS: 0 DISTRIBUTION: 0 EXEC: 0 IMAGES: 0 INFO: 0 NODES: 0 PLUGINS: 0 SECRETS: 0 SWARM: 0 SYSTEM: 0 VOLUMES: 0 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro networks: - socket-proxy
traefik: image: traefik:v3.6 depends_on: - socket-proxy command: - "--providers.docker.endpoint=tcp://socket-proxy:2375" # ...autres options networks: - socket-proxy - traefik-public
networks: socket-proxy: driver: bridge traefik-public: external: trueHealthchecks et load balancing
Section intitulée « Healthchecks et load balancing »Configuration des healthchecks
Section intitulée « Configuration des healthchecks »Traefik vérifie régulièrement la santé des backends :
labels: # Healthcheck HTTP - "traefik.http.services.api.loadbalancer.healthcheck.path=/health" - "traefik.http.services.api.loadbalancer.healthcheck.port=8080" - "traefik.http.services.api.loadbalancer.healthcheck.interval=10s" - "traefik.http.services.api.loadbalancer.healthcheck.timeout=3s"| Option | Description | Valeur par défaut |
|---|---|---|
path | Chemin à vérifier | / |
port | Port à vérifier | Port du service |
interval | Intervalle entre vérifications | 30s |
timeout | Timeout de la vérification | 5s |
Stratégies de load balancing
Section intitulée « Stratégies de load balancing »labels: # Round Robin (défaut) - "traefik.http.services.api.loadbalancer.strategy=round-robin"
# Sticky sessions (affinité) - "traefik.http.services.api.loadbalancer.sticky.cookie=true" - "traefik.http.services.api.loadbalancer.sticky.cookie.name=server_id" - "traefik.http.services.api.loadbalancer.sticky.cookie.secure=true"Dépannage
Section intitulée « Dépannage »Conteneur non détecté
Section intitulée « Conteneur non détecté »Symptômes : Le conteneur ne s’affiche pas dans le dashboard Traefik.
Vérifications :
-
Le label
traefik.enable=trueest présent ?Fenêtre de terminal docker inspect mycontainer | jq '.[0].Config.Labels' -
Le conteneur est sur le bon réseau ?
Fenêtre de terminal docker network inspect traefik-public -
exposedByDefaultest-il àtrueoufalse?
Erreur “Gateway timeout”
Section intitulée « Erreur “Gateway timeout” »Symptômes : Erreur 502 ou 504 après plusieurs secondes.
Causes possibles :
-
Port incorrect : Vérifiez le label
loadbalancer.server.port- "traefik.http.services.myapp.loadbalancer.server.port=8080" -
Réseau différent : Traefik et le conteneur ne sont pas sur le même réseau
- "traefik.docker.network=traefik-public" -
Application non démarrée : Vérifiez les logs du conteneur
Fenêtre de terminal docker logs mycontainer
Conflit de noms
Section intitulée « Conflit de noms »Symptômes : “router already exists” dans les logs Traefik.
Solution : Utilisez des noms uniques pour chaque router et service :
# Mauvais : même nom "app" pour deux services- "traefik.http.routers.app.rule=..." # Conflit !
# Bon : noms uniques- "traefik.http.routers.frontend-app.rule=..."- "traefik.http.routers.api-app.rule=..."Logs et debug
Section intitulée « Logs et debug »# Logs Traefikdocker logs traefik -f
# Niveau debugdocker run traefik:v3.6 --log.level=DEBUG
# Vérifier les routers via APIcurl http://localhost:8080/api/http/routers | jq
# Vérifier les servicescurl http://localhost:8080/api/http/services | jqÀ retenir
Section intitulée « À retenir »-
Labels = Configuration : Les labels Docker définissent le routage sans fichier de configuration externe
-
exposedByDefault: false : Toujours désactiver pour éviter d’exposer des conteneurs par accident
-
Réseau dédié : Créez un réseau
traefik-publicexterne et attachez-y tous les services à exposer -
traefik.docker.network : Obligatoire quand un conteneur est sur plusieurs réseaux
-
Socket proxy en production : Utilisez docker-socket-proxy pour sécuriser l’accès au daemon Docker
-
Noms uniques : Chaque router et service doit avoir un nom unique pour éviter les conflits
-
Healthchecks : Configurez-les pour retirer automatiquement les backends en échec
-
Swarm : Utilisez le provider
swarmavec labels dansdeploy.labels
Prochaines étapes
Section intitulée « Prochaines étapes »Bientôt : guides sur les middlewares de sécurité, la configuration TLS avancée, et l’observabilité avec Traefik.