Verwendung von Traefik als Reverse Proxy - Convention over Configuration

Insider Blog

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.yaml
services:
  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:

  • whoami ist der Name des "Haupt"-Dienstes (2)
  • whoami ist auch der Standard-Name des Compose-Projekts
  • Traefik wird aktiviert (5)
  • Der Dienst wird unter der Subdomain whoami bereitgestellt (6)
  • Die Auslieferung erfolgt über HTTPS (7)
  • Ein vorkonfigurierter Certresolver namens letsencrypt wird für tls verwendet (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 tls geschü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.

  1. Traefik aktivieren
  2. Eine Subdomain zuweisen
  3. 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.yaml
services:
  <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:

  1. app als Name des "Hauptcontainers", damit Traefik den Datenverkehr dorthin leitet
  2. <stack_name> (der Name des Compose-Projekts) in der Subdomain
(1) whoami/docker-compose.yaml
services:
  app:
    image: traefik/whoami

Nun konfigurieren wir Traefik, um "die Magie" wirken zu lassen:

(2) traefik/docker-compose.yaml
volumes:
  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:

  1. Wir konfigurieren einen Let's Encrypt Certificates Resolver (11-14)
  2. Wir hören auf Port 80 und 443 (16-17)
  3. Wir leiten den gesamten HTTP-Verkehr auf HTTPS um (19-20)
  4. Und binden den konfigurierten Certificates Resolver daran (21)
  5. 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`)
  • .Name wird automatisch als <service-name>-<stack_name> generiert. Für dein whoami-Beispiel wäre das also app-whoami.
  • trimPrefix 'app-'.Name ergibt whoami.

--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.yaml
name: whoami # Projektname manuell setzen
services:
  app:
    image: traefik/whoami

Autor

Steckbrief

Veröffentlicht:

March 13, 2026

Kategorien:

Was uns bewegt, DevOps

Tags:

DevOps
Vorheriger Artikel