Traefik v2.0logo

Documentation utilisée.

Cette documentation n'a pas pour but d'être exhaustive, mais uniquement d'expliquer les principes derrière traefik v2.0, ainsi que certaines portions qui nous semblent les plus intéressantes.

Redirection via **traefik v2.0**

Voici la gestion d'une redirection par Traefik v2.0. Une requête arrive de l'utilisateur via un entrypoint (en pratique, le port 80 ou 443). En fonction de l'URL demandée par la requête, elle est redirigée vers un router qui lui-même l'envoie potentiellement à un ou plusieurs middleware (permettant par exemple de gérer une authentification) avant d'arriver au service concerné (dans notre cas, un conteneur docker).

En parallèle, traefik v2.0 peut gérer les certificats ssl via un certificate resolver. Nous ne nous intéresseront ici qu'au cas de Let's Encrypt.

Nous montrerons ici comment lancer traefik v2.0 et comment configurer les différentes étapes de redirection via 3 fichiers :

  • traefik.yml : fichier de configuration de la partie statique de traefik v2.0 ;
  • middlewares.yml : fichier de configuration dans lequel nous mettrons tous nos middlewares ;
  • docker-compose.yml : fichier de configuration d'un des services pour lequel nous voulons une redirection.

Notons que nous pourrions arriver à un résultat similaire en n'utilisant que le fichier traefik.yml, ou uniquement des directives de docker-compose.yml. Nous présentons ici la méthode qui nous paraît la plus compréhensible et facile à maintenir.

Installation

Nous utilisons traefik v2.0 via son image docker, et le lançons via le fichier docker-compose.yml suivant :

# docker-compose.yml
version: "3.3"

services:
  traefik:
    image: "traefik:v2.0"
    restart: "unless-stopped"
    container_name: "traefik"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./data:/etc/traefik/"
      - "/var/run/docker.sock:/var/run/docker.sock"

Ici nous créons in conteneur appelé traefik utilisant l'image officielle. Nous publions les ports 80 et 443, nécessaires aux protocoles http et https respectivement. Enfin, nous créons deux volumes, l'un associé à un dossier local data qui contiendra les différents fichiers de configuration, et l'autre donnant accès à traefik v2.0 au docker de la machine hôte.

Configuration

Configuration statique

La configuration statique se fait via un fichier traefik.yml que nous stockerons dans le dossier data pour que le conteneur le retrouve sous le chemin /etc/traefik/traefik.yml.

# data/traefik.yml
entryPoints:
  web:
    address: ":80"
  web-secure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: "<email de contact>"
      storage: "/etc/traefik/acme.json"
      httpChallenge:
        entryPoint: web

api:
  insecure: true
  dashboard: true

providers:
  file:
    filename: "/etc/traefik/middlewares.yml"
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: web

Ce fichier est en quatre parties. La première définit les points d'entrée de traefik v2.0. Nous en créons un que nous appelons web correspondant au port 80, et un second que nous appelons web-secure correspondant au port 443.

La second partie permet de gérer la connection avec Let's Encrypt. Nous créons un certificateResolver appelé letsencrypt, nous lui fournissons un email de contact, lui indiquons de stocker les clefs dans le repertoire /etc/traefik qui n'est pas supprimé lors de l'arrêt du conteneur, et enfin lui fournissons le point d'entrée pour les challenges via http.

La troisième partie active la dashboard de traefik.

La quatrième partie quant à elle liste les fournisseurs de règle. Traefik v2.0 peut travailler avec différents logiciels ou orchestrateurs, et il est nécessaire de lui indiquer lesquels prendre en compte. Nous en déclarons deux ici :

  • Le fichier /etc/traefik/middlewares.yml qui contient les différents middlewares que nous voudrons utiliser ;
  • Le démon docker, pour lequel nous précisons que nous ne voulons pas que les conteneurs soient exposés par défaut, et auquel nous précisons d'utiliser le réseau web.

Configuration des middlewares

Nous allons créer deux middleware que nous pourrons utiliser par la suite dans autant de redirection que voulu. Il n'est cependant pas nécessaire de créer de middlewares, auquel cas il faudrait soit créer un fichier data/middlewares.yml vide, soit retirer le "file provider" du fichier de configuration statique.

# data/middlewares.yml
http:
  middlewares:
    redirect:
      redirectScheme:
        scheme: https
    admin-auth:
      basicAuth:
        users:
         - "admin:$apr1$a1GBk512$7iY9nX7AAN7eC0PSkDV1D0"
         - "user:$apr1$pIEqNGcM$gxsdyrR0EiDvqeHj72d.g1"

Ce fichier créer donc deux middlewares appelés redirect et admin-auth (ces noms sont arbitraires et n'ont pas d'incidence sur les middlewares). Un router utilisant le premier redirigera tout son trafic vers du https. Un router utilisant le second ne sera accessible qu'après authentification, les paires d'utilisateurs / mot de passe valides étant décrites dans le tableau users. On peut créer une telle pair via l'utilitaire htpasswd :

htpasswd -nb <utilisateur> <mot de passe>

D'autres middlewares sont disponibles et décrit dans la documentation officielle.

Configuration des services docker

Un service docker peut se déclarer auprès de Traefik v2.0 via ses labels et son réseau. Tout d'abord, un service à exposer doit faire partie du réseau web, tel que déclaré dans le fichier de configuration statique. De plus, le premier label nécessaire est celui disant à Traefik v2.0 d'exposer ce service :

"traefik.enable=true"

Nous allons ensuite pouvoir ajouter des labels pour créer un router correspondant au trafic http:

"traefik.http.routers.web-<service>.rule=Host(`<service.domain.tld>`)"
"traefik.http.routers.web-<service>.entrypoints=web"

Ici, <service> est un identifiant unique pour le service, alors que <service.domaine.tld> est le sous-domaine via lequel on veut pouvoir accéder au service ; web est le point d'entrée http tel que déclaré dans le fichier de configuration statique.

Notons que si l'ont veut utiliser un path prefix pour accéder au service plutôt qu'un sous-domaine, le label deviendrait :

"traefik.http.routers.web-<service>.rule=Host(`<service.domain.tld>`) && PathPrefix(`/<prefix>`)"

Si on veut une redirection http vers https, on peut utiliser le middleware créé précedemment :

"traefik.http.routers.web-<service>.middlewares=redirect@file"

Le @file rajouté à la fin du nom du middleware permet de dire à Traefik v2.0 d'aller chercher le middleware dans un file provider.

De la même manière, on peut créer un router pour le trafic https:

"traefik.http.routers.web-secure-<service>.rule=Host(`<service.domaine.tld`)"
"traefik.http.routers.web-secure-<service>.entrypoints=web-secure"
"traefik.http.routers.web-secure-<service>.tls=true"
"traefik.http.routers.web-secure-<service>.tls.certresolver=letsencrypt"

Les instructions supplémentaires sont celles permettant d'utiliser tls ainsi que Let's Encrypt comme fournisseur de certificats. Si l'on désire limiter l'accès au service à un groupe créé précédemment, on peut ajouter le label suivant : 

"traefik.http.routers.web-secure-<service>.middlewares=admin-auth@file"

Enfin, pour spécifier à Traefik v2.0 vers quel port du conteneur rediriger, si ce dernier n'est pas le port 80, il faut ajouter un service au router :

"traefik.http.routers.web-secure-<service>.service=<service>"
"traefik.http.services.<service>.loadbalancer.port=<port>"

<port> est le port vers lequel rediriger.

Par exemple, pour un service whoami accessible viar l'url whoami.bobbyblues.com uniquement en https après authentification, on utiliserait le docker-compose.yml suivant :

# whoami/docker-compose.yml
version: 3

networks:
  web:
    external: "true"

services:
  whoami:
    image: "containous/whoami"
    container_name: "whoami"
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.web-whoami.rule=Host(`whoami.bobbyblues.com`)"
      - "traefik.http.routers.web-whoami.entrypoints=web"
      - "traefik.http.routers.web-whoami.middlewares=redirect@file"
      - "traefik.http.routers.web-secure-whoami.rule=Host(`whoami.bobbyblues.com`)"
      - "traefik.http.routers.web-secure-whoami.entrypoints=web-secure"
      - "traefik.http.routers.web-secure-whoami.tls=true"
      - "traefik.http.routers.web-secure-whoami.tls.certresolver=letsencrypt"
      - "traefik.http.routers.web-secure-whoami.middlewares=admin-auth@file"

Un autre exemple, pour avoir accès au dashboard Traefik v2.0, accessible sur le port 8080 du conteneur, le docker-compose.yml deviendrait :

# docker-compose.yml
version: "3.3"

services:
  traefik:
    image: "traefik:v2.0"
    restart: "unless-stopped"
    container_name: "traefik"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./data:/etc/traefik/"
      - "/var/run/docker.sock:/var/run/docker.sock"
    labels:
      - "traefik.enable=true"
      # http labels
      - "traefik.http.routers.web-traefik.rule=Host(`traefik.bobbyblues.com`)"
      - "traefik.http.routers.web-traefik.entrypoints=web"
      - "traefik.http.routers.web-traefik.service=testservice"
      - "traefik.http.routers.web-traefik.middlewares=redirect@file"
      # https labels
      - "traefik.http.routers.web-secure-traefik.rule=Host(`traefik.bobbyblues.com`)"
      - "traefik.http.routers.web-secure-traefik.entrypoints=web-secure"
      - "traefik.http.routers.web-secure-traefik.tls=true"
      - "traefik.http.routers.web-secure-traefik.tls.certresolver=letsencrypt"
      - "traefik.http.routers.web-secure-traefik.service=testservice"
      # Services
      - "traefik.http.services.testservice.loadbalancer.server.port=8080"

Ici, on redirige le http vers du https, on utilise letsencrypt pour les certificats, et enfin on utilise notre service testservice qui redirige vers le port 8080.