Mes débuts avec Traefik
2020-04-29T00:08:08+02:00 | 9 minutes de lecture | Mise à jour le 2020-04-29T00:08:08+02:00
Je partage avec vous mes débuts avec le “Edge Router” Traefik dans sa version 2.X.
Introduction
Traefik est un reverse-proxy open source écrit en Go,
on le qualifie aussi de Edge Router.
Son logo nous le prouve :
Dans sa version 1, il reroutait seulement les requêtes HTTP(S). Depuis la version 2, cela fonctionne pour toutes applications de type TCP.
Faire un article sur Traefik n’est pas des plus simple…
C’est pour cela que je vais le faire en plusieurs parties
(au fur et à mesure de mon apprentissage sur la solution).
Afin ce vous exposer au mieux le fonctionnement,
on va déployer quelques conteneurs Nginx qui seront accessibles via Traefik.
Avant cela, nous allons lancer Traefik avec son dashboard équipé
d’une authentification basique.
Cela nous permettra de comprendre les concepts de Traefik.
[!WARNING] Cet article ne traite pas la partie HTTPS.
Je vous conseille de suivre ce tutoriel sur une machine Linux avec un navigateur Web. Pour me compliquer la vie, je l’ai fait sur une Lubuntu 20.04.
Préparation
Pour pouvoir exécuter les exemples de ce tutoriel,
il faut que vous ajoutiez quelques entrées dans votre fichier /etc/hosts
.
sudo cp /etc/hosts /etc/hosts.bak # on fait une backup !
echo "#### <Traefik tests> ####" | sudo tee -a /etc/hosts
echo "127.0.0.1 traefik.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 pgo.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 hommell.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 site-audi.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 bmw-site.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 trucexterne.example.com" | sudo tee -a /etc/hosts
echo "#### </Traefik tests> ####" | sudo tee -a /etc/hosts
🚗 Ces noms font référence à des marques de voitures (à part “trucexterne”…). 🚗
On vérifie nos nouvelles entrées :
for i in traefik pgo hommell site-audi bmw-site; do ping -c 1 ${i}.example.com &> /dev/null && echo OK || echo FAIL $i; done
Bien sur, il vous faut Docker ainsi que Docker Compose :
sudo apt update
sudo apt install docker.io docker-compose
systemctl start docker
systemctl enable docker # active le lancement de Docker au boot
Traefik
Premier lancement
Traefik demande l’accès au socket Docker, il faudra donc lancer le docker-compose en tant que root.
Je travaille dans l’environnement suivant :
sudo -i # on passe en root
mkdir -p docker/traefik
cd docker/traefik
Créons donc notre docker-compose.yml
à l’image du quick-start de la
documentation officiel :
version: '3'
services:
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.2
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
# The HTTP port
- "80:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
On lance donc notre docker-compose (docker-compose up -d
).
On navigue ensuite sur le port 8080 (http://localhost:8080)
qui donne accès au dashboard de manière non sécurisé.
Le port 80 ne donne rien car nous n’avons aucun service routé dessus pour l’instant.
Si cela fonctionne, vous êtes prêt à passer aux choses sérieuses.
On prend donc un Doliprane et on détruit notre conteneur avec un docker-compose down
.
Dashboard authentifié
Concepts
La solution peut se paramétrer de plusieurs façons. Vous trouverez trois méthodes :
- Configuration statique
- Configuration dynamique par fichier
- Configuration dynamique par labels (Docker)
La force de Traefik réside dans son caractère dynamique :
une fois bien paramétré et lancé, plus besoin de le recharger à chaque
ajout de nouveaux services (pas de systemctl apache reload
par exemple).
On va ici couvrir les trois façons de faire de la manière respective suivante :
- Configuration de Traefik
- Configuration de l’authentification du dashbord
- Configuration de services supplémentaires (partie suivante)
Application
On modifie donc notre docker-compose.yml
de la manière suivante :
version: '3'
services:
reverse-proxy:
# Traefik v2.2 officiel
image: traefik:v2.2
ports:
# Ports d'écoute
- "80:80"
# Dashboard
- "8080:8080"
volumes:
# Mapping de la configuration statique
- ./traefik.yml:/etc/traefik/traefik.yml
# Mapping du dossier de conf dynamique
- ./dyn_traefik/:/etc/dyn_traefik/
# Pour que traefik puisse écouter les events Docker
- /var/run/docker.sock:/var/run/docker.sock
On simplifie donc ce fichier en enlevant la directive command:
.
Les informations relatives seront spécifiées dans le fichier traefik.yml
.
Le dossier dyn_traefik
contiendra les fichiers de configuration dynamique :
un seul dans notre cas, celui du dashbord qui représente notre premier service.
On crée donc le fichier traefik.yml
dans notre dossier de travail avec
le contenu suivant :
entryPoints:
web:
address: ':80'
dashboard:
address: ':8080'
log:
# Default: "ERROR"
level: INFO
api:
dashboard: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
# Expose containers by default in traefik
exposedByDefault: true
# Enable the file provider to define routers / middlewares / services in file
file:
directory: /etc/dyn_traefik/
watch: true
Vous verrez souvent ce fichier au format TOML, j’ai préféré le faire en YAML
pour rester cohérent avec les autres fichiers déjà dans ce langage.
J’ai mis les logs au niveau “INFO” pour avoir un peu plus d’info au cas où.
L’option watch: true
permets de dire à Traefik d’être à l’écoute des modifications
sur le dossier.
On créer donc ensuite le dossier dyn_traefik
. Dedans, j’ai crée un fichier dashboard.yml
comme ceci :
http:
routers:
api:
rule: "Host(`traefik.example.com`)"
service: api@internal
middlewares:
- auth
middlewares:
auth:
basicAuth:
users:
- "admin:$2y$10$sqgVdrmQxXQgYIpg3BycVuZ2J8sFSHheVnmd728KkE7fznFSlxA0u"
- "test:$2y$10$mPcvlMccO2mXjA2ye.uBWuhO36x46K/3b.g1AjJ1YllmKCSAuS.vG"
De par cette configuration, le dashboard sera accessible depuis l’URL traefik.example.com et bénéficiera d’une authentification basique avec les comptes “admin” et “test” dont les mots de passe sont respectivement “admin” et “test”.
Pour la génération des hashs de mots de passe, je vous renvoie sur un autre de mes articles.
Un coup de docker-compose up -d
et testez l’accès à votre dashboard.
Cool non ? 😎
Ajout de conteneurs “internes”
On va maintenant ajouté deux services à notre fichier Docker Compose.
Ces deux services seront simplement des serveurs Nginx
avec des pages Web spécifiques pour bien les identifier.
On ajoute donc le contenu suivant à la suite du fichier :
pgo:
image: nginx:alpine
volumes:
- ./index-pgo.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.pgo.rule=Host(`pgo.example.com`)
hommell:
image: nginx:alpine
volumes:
- ./index-hommell.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.hommell.rule=Host(`hommell.example.com`)
Les “labels” sont là pour configurer Traefik dynamiquement.
La ligne la moins évidente est :
traefik.http.routers.<nom_du_conteneur>.rule=Host(`<une_url>`)
Ecris comme ci-dessus, c’est plus parlant non ?
On crée donc les pages d’accueil pour nos sites Web :
echo "<h1>Prévôt : Gilles et Olivier</h1>" > index-pgo.html
echo "<h1>Automobiles Michel Hommel</h1>" > index-hommell.html
Ainsi, on actualise notre Docker Compose (pas besoin de le stopper ou le détruire) avec la commande habituel.
Le dashboard devrait montrer les nouvelles entrées dans la section des routeurs et les URLs (pgo.example.com & hommell.example.com) devraient bien renvoyer sur leurs sites respectifs.
Vous remarquerez que nous n’avons pas eu à mapper les ports 80 des conteneurs.
C’est normal car les conteneurs ont été créer dans le même réseau (“network”)
que celui de Traefik (car on est dans le même docker-compose.yml
).
De ce fait, c’est bien notre aiguilleur Traefik qui effectue le routage.
[!IMPORTANT] Du coup, je dois mettre toutes mes définitions de conteneur dans le même Docker Compose ?
La réponse et non et c’est ce que nous allons voir dans la partie suivante.
Ajout de conteneurs “externes”
Modification du Docker Compose
Pour avoir la possibilité de connecter d’autres conteneurs à notre reverse-proxy
nous allons utiliser les réseaux au sein de Docker.
On créer donc une définition de réseau autoroute
en bridge qu’on nommera motorway
(vous comprendrez pourquoi après 😉).
Cette fonctionnalité nécessite est introduite en version 3.5 de Docker Compose.
J’ai donc aussi changé la version de mon fichier à la dernière que je peux :
3.7 vu que j’ai la version 1.25 de Docker Compose.
On détruit notre stack actuelle avec un docker-compose down
et on modifie le fichier.
Voici donc mon fichier actualisé :
version: '3.7'
services:
reverse-proxy:
# Traefik v2.2 officiel
image: traefik:v2.2
ports:
# Ports d'écoute
- "80:80"
# Dashboard
- "8080:8080"
volumes:
# Mapping de la configuration statique
- ./traefik.yml:/etc/traefik/traefik.yml
# Mapping du dossier de conf dynamique
- ./dyn_traefik/:/etc/dyn_traefik/
# Pour que traefik puisse écouter les events Docker
- /var/run/docker.sock:/var/run/docker.sock
networks:
- autoroute
pgo:
image: nginx:alpine
volumes:
- ./index-pgo.html:/usr/share/nginx/html/index.html
labels:
- traefik.http.routers.pgo.rule=Host(`pgo.example.com`)
- traefik.port=80
- traefik.enable=true
networks:
- autoroute
hommell:
image: nginx:alpine
volumes:
- ./index-hommell.html:/usr/share/nginx/html/index.html
labels:
- traefik.http.routers.hommell.rule=Host(`hommell.example.com`)
- traefik.port=80
- traefik.enable=true
networks:
- autoroute
networks:
autoroute:
driver: bridge
name: motorway
On “up” tous cela et on vérifie que nos trois services sont toujours accessibles avant de passé à la suite.
Création d’un autre Docker Compose
On se positionne donc dans un autre dossier et on crée les fichiers pour Audi et BMW à l’image de ceux de PGO et Hommel :
mkdir -p ../allemandes && cd ../allemandes
echo "<h1>Auto Union Deutsches Industrie</h1>" > index-audi.html
echo "<h1>Bayerische Motoren Werke</h1>" > index-bmw.html
Et le docker-compose.yml
:
version: '3.7'
services:
audi:
image: nginx:alpine
volumes:
- ./index-audi.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.audi.rule=Host(`site-audi.example.com`)
networks:
- autobahn
bmw:
image: nginx:alpine
volumes:
- ./index-bmw.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.bmw.rule=Host(`bmw-site.example.com`)
networks:
autobahn:
external:
name: motorway
Après avoir lancé ce Docker Compose, on teste l’accessibilité des sites Web
des voitures allemandes et on se rend compte que celui de BMW ne fonctionne pas !
Cela est dû au fait que BMW n’est pas dans l’autobahn
(que le conteneur n’est pas dans le réseau défini).
Je prends cet exemple un peu trop à cœur…
[!TIP] Containous (la société derrière Traefik), PGO et Hommell sont françaises alors qu’Audi et BMW sont allemandes.
Les deux docker-compose représentent donc la France et l’Allemagne ! D’où les noms de réseau dans leur langue officielle respective et un nom de réseau commun ("motorway") dans la langue internationale.
Vous comprenez donc que, par cet exemple, qu’il n’est plus nécessaire de toucher au conteneur Traefik. L’idéal serait donc surement d’avoir une composition avec Traefik seul.
Ajout de services externe
Pour finir, nous allons faire un reverse-proxy du contenu d’un serveur externe.
J’ai donc lancé un Nginx sur un autre serveur avec un simple docker run
:
docker run --name tteesstt -d -p 999:80 nginx:alpine
J’ai ensuite vérifié que j’ai bien accès au contenu depuis le serveur où Traefik est installé en naviguant sur l’adresse IP du serveur et le port spécifié.
On va donc créer un nouveau fichier de configuration dynamique
dans le dossier dyn_traefik
.
J’ai appelé le mien azerty.yml
et son contenu est le suivant :
http:
services:
administration:
loadBalancer:
servers:
- url: "http://192.168.92.17:999/"
routers:
administration:
rule: "Host(`trucexterne.example.com`)"
service: administration@file
J’ai référencé cette application sous le nom administration
parce que j’avais pas d’idée.
Le @file
précise qu’on utilise le provider “file” (cf. traefik.yml
).
Destruction
Docker
Sur le serveur externe :
docker stop tteesstt
docker system prune --all --volumes # Supprime tout ce qui n'est pas utilisé
Sur le serveur où Traefik et lancé :
# En me positionnant dans le dossier `docker`
cd allemandes && docker-compose down && cd ..
cd traefik && docker-compose down && cd ..
docker system prune --all --volumes
Au cas ou vous voulez supprimer les fichiers de configuration :
rm -rf ./*
N’oubliez pas d’effacer les entrées de votre fichier /etc/hosts
.
Si vous avez fait comme moi :
mv /etc/hosts /etc/hosts.old && mv /etc/hosts.bak /etc/hosts
rm /etc/hosts.old
Conclusion
Cet article montre donc (à ma façon) comment utiliser Traefik.
Cet outil est très puissant et a donc une prise en main
qui n’est pas des plus simple…
De plus la documentation officielle n’aide pas vraiment.
Un prochain tutoriel sur Traefik (plus court j’espère) présentera Traefik en HTTPS via des certificats Let’s Encrypt avec surement d’autres options de routages.