Traefik

Avec docker compose, vous avez vu comment déclarer des services, les « scaler », .. Pour pouvoir déployer une application, vous avez croisé haproxy pour :

  • l’équilibrage de charge,

  • un routage qui dépend de la requête http (le conteneur questionné dépend de la route demandée),

  • la gestion des certificats TLS (souvent un peu compliqué) ..

Traefik répond à tous ces besoins, en un peu plus simple.

Vous allez avoir ici un petit aperçu de ce qui est possible et de son fonctionnement.

Écrivez le docker-compose suivant :

services:
  reverse-proxy:
    # The official v2 Traefik docker image
    image: traefik:v2.7
    # 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

Lancez le service reverse-proxy : docker compose up -d reverse-proxy

Ce faisant, vous avez lancé le conteneur traefik qui :

  • écoute sur le port 80 de votre machine et sur le port 8080.

  • a un accès à l’API docker de votre machine (via le montage de /var/run/docker.sock)

Pour le moment, rien d’intéressant sur le port 80. Et sur le port 8080, vous avez une interface de gestion de traefik (rien d’intéressant non plus).

Traefik écoute tout ce qui se passe sur l’API docker et détecte lorsque vous lancez de nouveaux conteneurs. Il regarde alors les labels associés, et se configure en conséquence.

Par exemple, ajoutez les lignes suivantes à votre docker-compose.yml:

whoami:
  # A container that exposes an API to show its IP address
  image: traefik/whoami
  labels:
    - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

Remarquez la partie « labels », elle permettra à traefik de se configurer. Lancez le service : docker compose up -d whoami

Rendez-vous à l’adresse whoami.docker.localhost : le proxy traefik transmet les requêtes qui lui sont faites vers whoami. Pas mal déjà !

Modifiez le service whoami pour qu’il y ait plusieurs répliques :

whoami:
  # A container that exposes an API to show its IP address
  image: traefik/whoami
  labels:
    - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
  deploy:
    replicas: 2

Lancez à nouveau les services. Constatez le fonctionnement « round robin » de l’équilibrage de charge !

Et ce n’est qu’une toute petite partie de ce que permet Traefik..

Pour essayer, mettez en place une application web dont le contenu dynamique est servi par un conteneur et le contenu static est servi par un autre conteneur. Pour cela, vous utiliserez les règles traefik de la forme

"(Host(`example.org`) && Path(`/machin`))"

Voir également :

Traefik dans un compose séparé

Dans le cas où vous avez plusieurs applications dockerisées, vous souhaiterez avoir un reverse proxy commun à toutes les applications.

Pour cela, vous aurez un docker compose pour traefik, puis un docker compose par « application »

services:

  traefik:
    image: "traefik:v2.9"
    container_name: "traefik"
    command:
      #- "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "8001:80"
      - "8087:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - frontends

networks:
  frontends:
    name: public

Puis par exemple pour une application whoami :

services:
  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    networks:
      - public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=web"

networks:
  public:
    external: true

Et pour une deuxième application :

services:
  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    networks:
      - public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`deuxieme.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=web"

networks:
  public:
    external: true

Traefik pour le code de la démo précédente

services:
  reverse-proxy:
    # The official v2 Traefik docker image
    image: traefik:v2.7
    # Enables the web UI and tells Traefik to listen to docker
    command: --api.insecure=true --providers.docker
    ports:
        - "80:80"
        - "8080:8080"
    volumes:
        # So that Traefik can listen to the Docker events
        - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
        - public

  frontend: # <- le nom du conteneur
      image: image_frontend_demo
      ports:
          - "80"
      labels:
        - "traefik.http.routers.frontend.rule=Host(`demo.localhost`) && PathPrefix(`/`)"
      networks:
         - public
  database:
      image: postgres:15
      ports:
          - "5432"
      environment:
          - POSTGRES_PASSWORD=toto
      networks:
         - db_network
  backend:
      image: image_backend_demo
      ports:
          - "8080"
      environment:
        - POSTGRES_SERVER=database
        - POSTGRES_DB=postgres
        - POSTGRES_USER=postgres
        - POSTGRES_PASSWORD=${MACHIN}
      labels:
        - "traefik.http.routers.backend.rule=Host(`demo.localhost`) && PathPrefix(`/api`)"
      networks:
         - public
         - db_network


  init_db:
        image: postgres
        environment:
          - POSTGRES_SERVER=database
          - POSTGRES_DB=postgres
          - POSTGRES_USER=postgres
          - POSTGRES_PASSWORD=toto
          - PGPASSWORD=toto
          - |
            INIT_DB=
            CREATE TABLE utilisateur( nom TEXT );
            INSERT INTO utilisateur VALUES ('bonjour');
            INSERT INTO utilisateur VALUES ('tout');
            INSERT INTO utilisateur VALUES ('le');
            INSERT INTO utilisateur VALUES ('monde');
        command: sh -c "echo $$INIT_DB | psql -U $$POSTGRES_USER -h $$POSTGRES_SERVER $$POSTGRES_DB"
        profiles:
           - tache_administration
        networks:
           - public

networks:
  db_network:
  public: