Traefik ist ein Reverse Proxy mit exzellenter Docker-Integration. Er verwendet Labels, die an Containern angebracht sind, um den Datenverkehr zu ihnen zu leiten.
Ein typisches Set an Labels sieht ungefähr so aus:
whoami/docker-compose.yamlservices:
whoami:
image: traefik/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls=true"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
In diesem Beispiel:
whoamiist der Name des "Haupt"-Dienstes (2)whoamiist auch der Standard-Name des Compose-Projekts- Traefik wird aktiviert (5)
- Der Dienst wird unter der Subdomain
whoamibereitgestellt (6) - Die Auslieferung erfolgt über HTTPS (7)
- Ein vorkonfigurierter Certresolver namens
letsencryptwird fürtlsverwendet (8-9)
Das Problem
In meinem anderen Beitrag über GitOps mit Docker habe ich das Konzept eingeführt,
git als „Source of Truth“ für Docker-Deployments mittels Docker Compose zu nutzen.
Dabei gibt es einige Anforderungen:
- Jeder Stack ist unter
<stack_name>.<your_domain>erreichbar - Jeder Stack ist mit
tlsgeschützt
Wir könnten zwar in jeder docker-compose.yaml die Labels manuell hinzufügen, doch dabei zeigt sich schnell,
dass wir die Konfiguration redundant wiederholen.
- Traefik aktivieren
- Eine Subdomain zuweisen
- HTTPS aktivieren
Die Lösung
Mit hilfe der $COMPOSE_PROJECT_NAME
Variable können wir ein generisches Template für eine solche Konfiguration erstellen.
Dadurch stellen wir sicher, dass die Traefik-Regeln einheitlich sind.
<stack_name>/docker-compose.yamlservices:
<main_service>:
labels:
- "traefik.enable=true"
- "traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`<stack_name>.example.com`)"
- "traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure"
- "traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true"
- "traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt"
Die gute Nachricht ist, dass Traefik es uns ermöglicht, einige Standardwerte zu konfigurieren, die den oben genannten Boilerplate-Code abdecken!
Führen wir zwei einfache Konventionen ein:
appals Name des "Hauptcontainers", damit Traefik den Datenverkehr dorthin leitet<stack_name>(der Name des Compose-Projekts) in der Subdomain
(1) whoami/docker-compose.yamlservices:
app:
image: traefik/whoami
Nun konfigurieren wir Traefik, um "die Magie" wirken zu lassen:
(2) traefik/docker-compose.yamlvolumes:
letsencrypt:
services:
traefik:
container_name: traefik
restart: always
image: traefik:3
network_mode: host
command:
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.email=<your_email_here>
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.http.tls.certresolver=letsencrypt
- --providers.docker
- --providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)
- --providers.docker.constraints=Label(`com.docker.compose.service`,`app`)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /letsencrypt:/letsencrypt
Erklären wir das ein wenig:
- Wir konfigurieren einen Let's Encrypt Certificates Resolver (11-14)
- Wir hören auf Port 80 und 443 (16-17)
- Wir leiten den gesamten HTTP-Verkehr auf HTTPS um (19-20)
- Und binden den konfigurierten Certificates Resolver daran (21)
- Wir richten den Docker-Provider ein (23-25)
Erklärung für die Zeilen 24-25
--providers.docker.defaultrule=Host(`{{ trimPrefix 'app-'.Name }}.example.com`)
.Namewird automatisch als<service-name>-<stack_name>generiert. Für deinwhoami-Beispiel wäre das alsoapp-whoami.trimPrefix 'app-'.Nameergibtwhoami.
--providers.docker.constraints=Label(`com.docker.compose.service`,`app`)
Alle Dienste sollten standardmäßig verfügbar sein, aber sie sollten gefiltert werden, sodass nur app-Dienste berücksichtigt werden. Das Label com.docker.compose.service wird von docker-compose automatisch zu allen Containern hinzugefügt.
Bonus-Konfiguration
Wir können diese Konfiguration noch weiter verfeinern.
Andere Dienste im Stack verfügbar machen
Manchmal möchte man mehr als nur den App-Container nach außen hin öffnen.
Die aktuelle Konfiguration leitet den Datenverkehr nur an unsere app-Dienste weiter.
Um weiterhin die Standard-Konfigurationsmethode nutzen zu können, müssen wir diese wieder aktivieren:
--providers.docker.constraints=Label(`com.docker.compose.service`,`app`) || Label(`traefik.enable`, `true`)
Stack-Name weicht vom Verzeichnisnamen ab
Beim Deployment der Stacks wird der Name basierend auf dem Verzeichnisnamen generiert, in dem sich die docker-compose.yaml Datei befindet.
Wir können den Namen auf verschiedene Arten ändern, aber hier ist die einfachste:
whoami-example/docker-compose.yamlname: whoami # Projektname manuell setzen
services:
app:
image: traefik/whoami
