Traefik
Présentation
Doc officielle niveau "débutant stupide"
Traefik est un reverse-proxy pour Docker, et pour les conteneurs en général. Son but est de pouvoir interagir avec les conteneurs pour en déduire automatiquement les routes à proposer; ainsi, on n'expose que le port de traefik, et il en déduit seul (ou avec un peu d'aide) comment donner accès à nos conteneurs.
Il fait cela en écoutant l'API de docker. C'est, à l'instar de Watchtower, un petit conteneur tout simple à installer, mais qui peut nous faciliter la vie.
Il propose également une interface web fort sympathique.
Mise en place (simpliste)
Le conteneur n'est pas compliqué à mettre en place. Il a seulement besoin d'un volume lui donnant accès à l'API de Docker. <source lang="yaml"> version: '3'
services:
reverse-proxy: # The official v2 Traefik docker image image: traefik:latest # 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
</source>
Ce fichier docker-compose sert simplement à faire tourner le conteneur traefik... Mais... Comment accéder à nos services via le port 80 de notre traefik (le port 8080 étant pour l'interface web) ?
Accéder à une (des) applications
Mettons que j'ai un FreshRSS, que je veux mettre derrière mon conteneur traefik. Sur le même serveur, je ferais un fichier docker-compose dédié. <source lang="yaml"> --- version: "3" services:
freshrss: restart: always image: ghcr.io/linuxserver/freshrss container_name: freshrss environment: - PUID=1000 - PGID=1000 - TZ=Europe/London volumes: - ./config:/config restart: always
</source>
Dès que je le lance traefik le repère (on le voit dans l'interface web !). À partir de ce moment, je pourrais avoir accès à mon freshrss grâce à Traefik, car il a déduit deux choses:
- Le port : notez que pour freshrss, nous ne bindons aucun port, même si FreshRSS parle normalement sur le port 80. En effet, traefik regarde quels ports expose le conteneur freshrss (lesquels sont ouverts sur celui-ci); si il n'en expose qu'un seul (c'est le cas ici et c'est le 80), il va le prendre en compte.
- Le vhost : pour accéder à tel service plutôt qu'un autre, j'ai besoin de le distinguer grâce à son vhost. Ici, pas de magie : par défaut, traefik se base sur le nom du service et sur le nom du conteneur associé. Ici, il a déduit le nom "freshrss-freshrss".
Un peu de config
Bon, super. Mais si j'ai plusieurs ports exposés par mon conteneur et que je veux un vhost que je choisis ? Viennent ici les labels. Les labels sont des métadonnées; plus simplement, des étiquettes que l'on peut coller sur nos conteneurs et dont le contenu est libre. Traefik les utilise pour déduire sa configuration. Ainsi, mon service freshrss va pouvoir, avec les bons labels, porter sa configuration traefik.
cf la doc, elle est bien faite, il y'a une liste de labels possibles.
Par exemple, pour définir nous même le port à interroger sur le conteneur, le label est :
traefik.http.services.<service_name>.loadbalancer.server.port
Par exemple
- "traefik.http.services.freshrss.loadbalancer.server.port=80"
Ici, <service_name> va définir, au sein de traefik, le nom du service associé à mon conteneur (freshrss en l'occurence). C'est un nom à définir nous-même : il convient de le faire correspondre avec le nom de notre service "freshrss" (défini dans le docker-compose de freshrss). Note : si je lui donne un port non exposé par le conteneur, il n'as pas l'air d'en tenir compte.
Pour le vhost, le label est :
traefik.http.routers.<service_name>.rule
Par exemple:
"traefik.http.routers.freshrss.rule=Host(`rss.tst.sq.lan`)"
Une fois notre fichier docker-compose.yml pour FreshRSS modifié, il donnerait donc: <source lang="yaml"> --- version: "3" services:
freshrss: restart: always image: ghcr.io/linuxserver/freshrss labels: - "traefik.http.routers.freshrss.rule=Host(`rss.ab.cd`)" - "traefik.http.services.freshrss.loadbalancer.server.port=80" container_name: freshrss environment: - PUID=1000 - PGID=1000 - TZ=Europe/London volumes: - ./config:/config restart: always deploy: resources: limits: memory: 200M reservations: memory: 200M
</source>
Et voilà : si je me rends sur le port 80 de traefik via l'adresse rss.ab.cd, je tombe sur mon freshrss.
L'interface web de traefik le prend tout de suite en compte, et je peux avoir des détails:
Dans l'optique ou un conteneur exposerait deux ports pour le web avec chacun une fonction, il doit être possible via les labels de créer deux services traefik associés (je n'ai pas essayé).
Networks
La galère peut survenir quand on a des conteneurs avec plusieurs réseau.
Le plus simple est d'avoir un réseau partagé avec traefik, et de préciser via un label sur le service web qu'il faut utiliser celui-là. Exemples.
Pour traefik: <source lang="yaml"> version: '3'
networks:
traefik: external: false
services:
reverse-proxy: # The official v2 Traefik docker image image: traefik:latest # Enables the web UI and tells Traefik to listen to docker command: - "--api.insecure=true" - "--providers.docker" - "--providers.docker.network=traefik" networks: traefik: 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
</source>
Pour mon service web: <source lang="yaml"> version: "3"
networks:
traefik_traefik: external: true db: external: false ipam: config: - subnet: 172.19.0.0/24
services:
server: image: gitea/gitea:1.15.3 container_name: gitea labels: - "traefik.http.routers.gitea.rule=Host(`gitea.squi.fr`)" - "traefik.http.services.gitea.loadbalancer.server.port=3000" - "traefik.docker.network=traefik_traefik" environment: - USER_UID=1000 - USER_GID=1000 restart: always networks: traefik_traefik: db: ipv4_address: 172.19.0.20 volumes: - ./gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro
</source> Pour ce second fichier, il faut regarder les labels : c'est le dernier qui est important. À noter qu'il s'agit d'un réseau externe, donc il s'appelle traefik_traefik, pas simplement traefik.