Introduction

Il y a 8 ans je vous faisais découvrir Docker. À l’époque je ne savais pas encore à quel point cet outil très controversé serait utilisé !

Docker est quasiment devenu un standard. Qu’on le veuille ou non il arrive souvent qu’on ait un conteneur Docker à lancer. On finit toujours par devoir lire la documentation de Docker.

Avant de continuer sur la problématique du présent article, je tiens à vous signaler qu’il est important de savoir un minimum jouer avec les fichiers docker-compose.yml. Cas échéant je crains que cet article ne vous soit d’aucune autre utilité que nourir votre curiosité.

Ainsi, un problème qui survient fréquemment quand on a crée nos images, nos conteneurs puis que nous lançons ces derniers : comment publier nos conteneurs afin qu’ils soient disponibles sur Internet ? En général la solution est d’utiliser un proxy (par exemple Nginx) qui va étudier les requêtes HTTP demandées sur le serveur puis rediriger vers le port choisi d’un conteneur Docker qu’on a lancé.

Image du logo de Traefik

Dans cet article je vais rapidement expliquer pourquoi le choix de Træfik plutôt que Nginx que j’utilisais avant ça. Ensuite j’expliquerai les configurations utilisées pour mettre à disposition nos conteneurs. Nous aborderons rapidement quelques points pour aller plus loin et finirons par une conclusion.

Choix du proxy

Habituellement, pour mettre en place l’accès à des sites web que j’héberge, j’utilisais Apache, Nginx ou encore Caddy.

Cependant il y avait pas mal de contraintes :

  • chaque nouveau domaine demandait une configuration spécifique avec un fichier spécifique, des dossiers spécifiques,
  • pour avoir un certificat SSL par Let’s Encrypt, il fallait parfois user d’intelligence, même une fois qu’on utilise Certbot, notamment pour redémarrer le serveur Web une fois les certificats renouvelés,
  • quand on lançait un conteneur Docker, il valait mieux choisir un port spécifique, par exemple 8081, puis recopier ce nombre en dur dans la configuration du serveur Web (Nginx dans mon cas) et je ne suis pas le plus imaginatif pour les numéros de ports qui se cumulaient…

Ce qui est assez pénible. Très consommateur de temps.

Étant donné que nous utilisons déjà les possibilités de Docker et Docker Compose, autant continuer en utilisant un outil ayant un backend avec Docker, non ?

C’est là que Træfik entre en jeu :

  • il permet avec quelques lignes dans vos fichiers docker-compose.yml de définir le domaine à utiliser pour tel ou tel conteneur Docker
  • il s’occupe de faire la demande de certificat Let’s Encrypt et le renouvellement de ces derniers
  • le lancement d’un conteneur Docker ne demande pas de relancer Træfik, il y a une détection automatique des configurations
  • on laisse les ports choisis par Docker pour nos conteneurs, ce qui nous évite d’en faire une gestion
  • étant codé en Go (tout comme Docker et Docker Compose), Træfik fait partie du même monde, il est donc aussi rapide et compatible avec les outils utilisés
  • pas besoin d’installer Træfik : il sera un conteneur Docker comme le reste des services de la machine :-)

Au final ce sont les contraintes des serveurs Web dont j’ai eu l’usage qui m’ont convaincu d’essayer Træfik. Voyons donc à quoi cela ressemble !

ATTENTION : Træfik ne résoud pas tous les problèmes du monde. Il va falloir expérimenter, recommencer plusieurs fois, plier son cerveau pour saisir de quoi il retourne. Parfois demander de l’aide. C’est un processus d’apprentissage qui en vaut la peine cependant !

Configuration de træfik

Pour mettre en place Træfik nous allons procéder comme la documentation de Træfik Proxy le propose :

  • faire un docker-compose.yml pour décrire notre service Træfik
  • utiliser un fichier de configuration externe pour configurer le service : le fichier traefik.yml
  • demander à exposer les ports 80 et 443

Pour cela, voici le fichier docker-compose.yml pour lancer le service Træfik :

version: '3'

services:
    proxy:
      image: traefik:v2.8
      restart: always
      ports:
      	- 80:80
        - 443:443
      volumes:
        # pour que Træfik écoute les événements Docker : à adapter chez vous
        - /var/run/docker.sock:/var/run/docker.sock
        # Utilisation d'un fichier de configuration
        - ${PWD}/traefik.yml:/etc/traefik/traefik.yml
        # Mémorisation des certificats TLS (par Let's Encrypt)
        - ${PWD}/acme.json:/acme.json
      labels:
        # Activation du tls
        - "traefik.http.routers.api.tls"
        # nawak, pour que les logs la boucle sur service error: port is missing
        - "traefik.http.services.nawak.loadbalancer.server.port=8484"

Ce qui va monter le fichier local /var/run/docker.sock pour discuter avec Docker : adaptez-le au fichier Socket de votre service Docker.

Cela va utiliser le fichier traefik.yml local qui contient notre configuration pour notre service Træfik.

On stocke les données des certificats dans le fichier local acme.json : pensez à faire touch acme.json pour créer le fichier avant de lancer.

Et voici le contenu de notre fichier traefik.yml :

api:
  dashboard: true # pour activer un tableau de bord

providers:
  docker:
    network: traefik # réseau de discussion entre les conteneurs et traefik
    exposedByDefault: false # n'active pas les conteneurs par défaut sur le web

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure # pointe sur websecure plus bas (port 443 en somme)
          scheme: https

  websecure:
    address: ":443"
    http:
      tls: # configuration par défaut
        certResolver: letsencrypt # pointe sur la config. letsencrypt plus bas

  traefik: # adresse pour le dashboard ;-)
    address: ":8080"

certificatesResolvers:
  letsencrypt:
    acme:
      email: "mon-courriel@domaine.tld"
      storage: "/acme.json"
      httpChallenge: # le type utilisé pour valider les certificats Let's Encrypt
        entryPoint: web

Je me suis permis de commenter un peu partout pour savoir de quoi il retourne.

Sachez qu’il existe aussi une méthode pour créer un fichier sur lequel Traefik va lire régulièrement pour mettre à jour sa configuration. Peut-être ferais-je un autre article sur ce sujet un jour. Petite piste : c’est le Provider nommé file qui permet de faire ça.

Une fois configuré, les autres conteneurs Docker que nous lançons n’ont plus besoin que des lignes suivantes dans leur fichier docker-compose.yml :

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.un-nom-de-service.rule=Host(`mon.domaine.com`)"
  - "traefik.http.routers.un-nom-de-service.entrypoints=websecure"

Au lancement de vos conteneurs via un fichier docker-compose.yml, Træfik lira les informations contenues dans labels et tentera de les analyser puis utiliser à bon essien.

Dans l’exemple donné ci-avant, on comprend que :

  • trafik.enable : le service doit être publié par Traefik (car dans la configuration nous avions mis exposedByDefault: false, donc pas de publication par défaut)
  • traefik.http.routers.un-nom-de-service.rule=Host(`mon.domaine.com`) : pour votre service remplacez un-nom-de-service par ce que vous voulez. Et mon.domaine.com par le domaine que vous détenez
  • la dernière ligne ne sert qu’à indiquer quel entrée par défaut accepter/utiliser. En l’occurence celle nommée websecure qui, dans notre configuration du fichier traefik.yml est configurée pour être disponible sur le port 443 avec un résolveur de certificat Let’s Encrypt

Exemple de docker-compose.yml pour lancer un service :

version: '3'

services:
    whoami:
      image: traefik/whoami
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.whoami.rule=Host(`whoami.domaine.com`)"
        - "traefik.http.routers.whoami.entrypoints=websecure"

Y aurait-il encore d’autres fonctionnalités sympas ?

Pour aller plus loin

Dans ce que j’ai pratiqué, voici quelques points à étudier pour aller plus loin :

  • utilisation de Let’s Encrypt par challenge DNS qui permet de gérer les DNS de son fournisseur de domaine en direct. Par exemple pour Gandi il suffit de fournir la variable d’environnement GANDIV5_API_KEY
  • utilisation d’un fichier externe avec watch: true pour appliquer les changements dès modification du fichier
  • utilisation de middleware pour une authentification basique
  • activer un port, par exemple 8080 pour l’accès au tableau de bord
  • dans certains cas où les services ne sont pas forcément dans des Docker, il peut être intéressant de fournir une IP et un port spécifique par un loadBalancer, Cf. https://doc.traefik.io/traefik/routing/services/#servers

Il a beaucoup plus à découvrir avec Træfik. Je vous invite à lire la documentation qui est très riche et bien expliquée.

Conclusion

Utiliser Træfik a permis de réduire considérablement le temps de maintenance de mes services, que ce soit en terme de mises à jour, de renouvellement de certificats et d’organisation des dossiers/fichiers.

Cependant qu’on se le dise, ce n’est pas exempt de quelques difficultés :

  • il n’y a pas toujours des images Docker de vos services, il faut donc parfois fabriquer soi-même les conteneurs,
  • la courbe d’apprentissage de Træfik est assez difficile,
  • on se casse les méninges jusqu’à comprendre comment fournir un service sur Træfik

Si on fait l’effort d’apprendre Træfik et d’investir du temps, c’est surtout pour assurer la possibilité de connecter tout cela à un système de métriques, pouvoir faire de la journalisation, vérifier l’état de santé des serveurs, etc.

Il y a de quoi faire !