Le tuto complet en version final est dispo ici
Je suis très longtemps resté sur mon bon vieux nginx pour faire mon reverse proxy, ça fonctionne parfaitement.
J'avais déjà testé traefik en version 1.5, et je l'avais trouvé plutôt lent et limité, mais récemment, je me suis dit que j'allais retesté tout ça, à l'heure ou j'écris ces lignes, nous sommes à la version 2.2, nommée chevrotin.
J'ai eu beaucoup de mal à bien comprendre le fonctionnement de traefik, car la quasi totalité des tutoriels sont identiques niveau configuration, ce qui changeait c'est l'application mis derrière. Mais aucun réel tutoriel qui en explique le fonctionnement. Nous allons ici tenter de réellement comprendre ce que nous faisons.
Je ne reviendrais sur ce qu'est traefik, si vous êtes tombé sur ce tutoriel, c'est que vous savez ce que c'est.
Vocabulaire
Pour comprendre le fonctionnement de traefik, nous aurons besoin d'un peu de vocabulaire :
les entrypoints
Les entrypoints sont comme le nom l'indique les points d'entrées, ce sont les adresses et ports exposés par traefik, qui permettrons d'exposer nos applications. Bien souvent nous utilisons les ports 443 et 80.
les services
Les services sont nos applications, par exemple nextcloud. Dans la version 1.X de traefik, c'était nommé les backends.
Nous avons 3 types de services :
Nous ne sommes donc pas limité au web, nous pouvons redirigé du ssh, du ftp , what else ?!!!
les routers
Les routers sont les règles de redirection du reverse, nous pointons un router vers un service. A ce router nous lui donnons des URLs, des entrypoints.
les providers
Les providers sont les sources de génération de la configuration. C'est ce qui fait la force de traefik, il en existe plusieurs, de plusieurs type :
- Moteur de conteneur :
- docker : La plus connu, on donne accès au socket de docker à traefik, et lui va gérer la création des services et routers en lisant celui-ci, en fonction des labels utilisés.
- kubernetes : Fonctionne de manière similaire à docker.
- rancher : Je n'ai pas encore regardé le fonctionnement, mais je suppose que le fonctionnement est identique à kubernetes
- marathon : Pareil que pour rancher
- Base de clé/valeur : Je n'ai pas regardé exactement le fonctionnement de ce type de provider
- consul
- consulcatalog
- etcd
- redis
- zookeeper
- file : Permets de lire un fichier ou un répertoire contenant des fichiers de configuration à la volée.
les middlewares
Les middlewares seront des étapes intermédiaires entre le router et le service, ça peux être un peu tout et n'importe quoi, comme de la compression, de la sécurisation, de la configuration, ou même de l'authentification (cela fera l'objet d'un autre article).
Configuration
Pour configurer traefik, nous avons deux méthodes, la méthode interactive, et la méthode déclarative.
Interactive
Cette méthode permets de passer la configuration directement en paramètre de l'exécutable, par exemple nous pourrions avoir ceci :
$ traefik --accesslog=true \
--api=true \
--api.insecure=true \
--api.dashboard=true \
--api.debug=true \
--log.level=INFO \
--providers.docker.endpoint=unix:///var/run/docker.sock \
--providers.docker.exposedbydefault=false \
--providers.docker.watch=true \
--providers.docker.swarmmode=true \
--providers.file.filename=/etc/traefik/traefik_dynamic.yml \
--providers.file.watch=true \
--entrypoints.web.address=:80 \
--entrypoints.websecure.address=:443 \
--entrypoints.web.http.redirections.entrypoint.scheme=https \
--entrypoints.web.http.redirections.entrypoint.to=websecure \
--certificatesresolvers.letsencrypt.acme.email=xataz@monmail.net \
--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory \
--certificatesresolvers.letsencrypt.acme.storage=/acme.json \
--certificatesresolvers.letsencrypt.acme.keytype=EC384 \
--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \
--certificatesresolvers.letsencrypt.acme.tlschallenge=true
C'est personnellement la méthode que j'utilise.
Bon cette méthode devient déclarative si on utilise docker et docker-compose.
Déclarative
Nous pouvons également passer un fichier de paramètre à traefik, au format toml
ou yaml
, ce qui donnerais pour la même configuration :
TOML
[accesslog]
[api]
insecure=true
dashboard=true
debug=true
[log]
level="INFO"
[providers]
[providers.docker]
endpoint="unix:///var/run/docker.sock"
exposedbydefault=false
watch=true
swarmmode=true
[providers.file]
filename=/etc/traefik/traefik_dynamic.yml
watch=true
[entryPoints]
[entryPoints.web]
address=":80"
[entryPoints.web.http.redirections.entrypoint]
scheme="https"
to="websecure"
[entryPoints.websecure]
address=":443"
[certificatesResolvers]
[certificatesResolvers.letsencrypt]
[certificatesResolvers.letsencrypt.acme]
email = "mail@nomdedomaine.org"
caServer = "https://acme-v02.api.letsencrypt.org/directory"
storage = "acme.json"
keyType = "EC384"
[certificatesResolvers.letsencrypt.acme.httpChallenge]
entryPoint = "web"
Perso je n'aime pas du tout ce format, c'est ce qui m'avait fait fuire traefik à l'époque.
YAML
accesslog: {}
api:
insecure: true
dashboard: true
debug: true
log:
level: "INFO"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedbydefault: false
watch: true
swarmmode: true
file:
filename: /etc/traefik/traefik_dynamic.yml
watch: true
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
scheme: "https"
to: "websecure"
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: "mail@nomdedomaine.org"
caServer: "https://acme-v02.api.letsencrypt.org/directory"
storage: "acme.json"
keyType: "EC384"
httpChallenge:
entryPoint: "web"
Je trouve le yaml beaucoup plus clair et simple.
Cas pratique
Rien de mieux qu'un exemple pour comprendre, nous allons faire une petite stack avec traefik, nextcloud et postgres.
Dans cette exemple, nous utiliserons docker pour installer les services, mais pas pour la configuration automatique de traefik.
Déjà je n'aime pas le fait de mettre mon socket docker dans un conteneur, même en lecture seul, le socket à toutes les informations des conteneurs. Autrement, je n'aime pas trop alourdir mes docker-compose, j'aime quand c'est clair, net et précis.
Nous partirons donc de cette configuration de docker-compose :
version: "3.8"
networks:
traefik:
services:
traefik:
image: traefik:chevrotin
volumes:
- /srv/docker/traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock
- /srv/docker/traefik/conf:/etc/traefik/conf
ports:
- 80:80
- 443:443
- 8080:8080 # le temps de tester
networks:
- traefik
command:
- "--global.sendanonymoususage=false" # désactivation de l'envoi de donnée
- "--global.checknewversion=false" # puisque dockerisé, on désactive le check de mise à jour
- "--accesslog=true" # Pour avoir les logs d'accès
- "--api=true" # Pour activer l'api
- "--api.insecure=true" # Activer pour exposer l'api sur 8080
- "--api.dashboard=true" # Pour activer le dashboard
- "--log.level=INFO"
- "--providers.file.directory=/etc/traefik/conf/" # Permets de charger les configurations dans le répertoire (tout les yaml et toml)
- "--providers.file.watch=true" # Permets de surveiller le répertoire précédent pour charger dynamiquement les configurations
- "--entrypoints.web.address=:80" # Création de l'entrypoint nommé web sur le port 80
- "--entrypoints.websecure.address=:443" # Création de l'entrypoint nommé websecure sur le port 443
#- "--entrypoints.web.http.redirections.entrypoint.scheme=https" # Pour créer une redirection vers https
#- "--entrypoints.web.http.redirections.entrypoint.to=websecure" # Pour rediriger vers l'entrypoint websecure (port 443)
# Le reste est la configuration de letsencrypt
- "--certificatesresolvers.letsencrypt.acme.email=contact@exemple.fr"
- "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
- "--certificatesresolvers.letsencrypt.acme.keytype=EC384"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
db_nextcloud:
image: postgres:12
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
networks:
- traefik
volumes:
- /srv/docker/db_nextcloud/:/var/lib/mysql
environment:
- POSTGRES_PASSWORD=nextcloud
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextcloud
nextcloud:
image: nextcloud:19
networks:
- traefik
environment:
- POSTGRES_HOST=db_nextcloud
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextcloud
- POSTGRES_PASSWORD=nextcloud
- NEXTCLOUD_ADMIN_USER=admin
- NEXTCLOUD_ADMIN_PASSWORD=admin
volumes:
- /srv/docker/nextcloud:/var/www/html
Maintenant que nous avons notre docker-compose