Einfaches Multi-Projekt-Setup mit Docker-Composite und Traefik.

Einfaches Multi-Projekt Setup mit Docker-Compose und Traefik

Um Projekte auf einem Server zu hosten gibt es viele Wege und keiner ist falsch. Gerade bei kleineren Projekten oder Servern hilft ein leichtgewichtiges und wartungsarmes Setup. Durch den Verzicht auf Skalierung kann auch auf große, ressourcenhungrige Tools wie Kubernetes verzichtet werden.

Um den Wartungsaufwand gering zu halten, setzt das Setup ausschließlich auf Docker und Docker-Compose.

Jedes Projekt erhält einen Ordner mit einer eigenen Docker-Compose. In dieser werden alle Container definiert. Der Traffic wird über Traefik zum jeweiligen Projekt geleitet. Die Konfiguration von Traefik ist live über Label in der jeweiligen Compose Datei möglich.

Wenn konfiguriert, kümmert sich Traefik automatisch um TLS Zertifikate per Let’s Encrypt.

Der spätere Verzeichnis Aufbau:

- projects
	- traefik
		- docker-compose.yml
		- traefik.yml
		- acme.json
	- projectA
		- docker-compose.yml

Netzwerk link

Docker-Compose ermöglicht es, Container in mehrere Netzwerke einzubinden. Für alle Container, die aus dem Internet erreichbar sein sollen, wird ein Netzwerk benötigt.

docker network create web

Proxy Traefik link

In einem eigenen Ordner für Traefik muss eine Docker-Compose docker-compose.yml Datei angelegt werden.

Traefik wird als einziger Container auf den Ports 80 und 443 lauschen und alle Anfragen intern weiterleiten. Damit Traefik live auf Änderungen reagieren kann, muss der Container Zugriff auf /var/run/docker.sock haben.

In der Datei acme.json speichert Traefik die Let’s Encrypt Zertifikate.

version: '3.7'

services:
  traefik:
    image: traefik:2.6
    restart: always
    ports:
      - 80:80
      - 443:443
    logging:
      options:
        max-size: "10m"
        max-file: "3"
    networks:
      - web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.yml:/traefik.yml
      - ./acme.json:/acme.json

networks:
  web:
    external: true

Konfiguration link

Traefik kann über Labels am Container konfiguriert werden. Einfacher geht es jedoch mit einer traefik.yml Datei.

Zunächst müssen die entryPoints definiert werden, an denen Traefik eingehenden Traffic erwartet. Neben HTTP(S) sind hier auch TCP/UDP Verbindungen möglich.

Als Provider ist Docker konfiguriert. Durch die Einstellung exposedByDefault: false werden Container erst öffentlich, wenn dies am Container aktiviert wird. Gibt einfach etwas mehr Sicherheit.

log:
  level: INFO

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  docker:
    exposedByDefault: false
    network: web
    endpoint: "unix:///var/run/docker.sock"
    watch: true

serversTransport:
  insecureSkipVerify: true

api:
  dashboard: true

accessLog: {}

TLS-Zertifikate link

An jedem Container kann definiert werden, wie das TLS Zertifikat entsteht. Für eine einfache Konfiguration kann hier ein ACME/Let’s Encrypt Resolver verwendet werden. Dieser erstellt auf dem HTTP-Endpunkt eine eigene Route, über die Let’s Encrypt die Domain verifizieren kann.

Läuft der Traefik in einem privaten Netzwerk, das von außen nicht erreichbar ist, kann hier auch der DNS Resolver verwendet werden. Dieser hinterlegt die benötigten Daten automatisch beim DNS-Server.

Folgender Codeausschnitt gehört an das Ende der Datei traefik.yml. Der gewählte Name des Resolvers (hier sample-resolver) wird später benötigt.

certificatesResolvers:
  sample-resolver:
    acme:
      email: <email@example.com>
      storage: /acme.json
      httpChallenge:
        # used during the challenge
        entryPoint: http

Start link

Wie gewohnt kann traefik nun mit Docker-Compose gestartet werden.

docker-compose up -d

Von nun an wird Traefik seine Konfiguration automatisch aktualisieren, wenn Projekte gestartet, beendet oder neu konfiguriert werden.

Projekte link

In den jeweiligen Projekt Ordnern kann wie gewohnt eine Docker-Compose Datei erstellt werden. Diese wird nur zusätzlich um Netzwerk und Labels erweitert.

version: '3.7'

services:
  app:
    # ...
    networks:
      - web
    labels:
      - traefik.enable=true
      - traefik.http.routers.my-container.rule=Host(`example.com`)
      - traefik.http.services.my-service.loadbalancer.server.port=12345
      - traefik.docker.network=web

networks:
  web:
    external: true

Netzwerk link

Unter dem Punkt networks kann eine Liste von Netzwerken definiert werden. Der zuvor erstellte Traefik Server befindet sich im Netzwerk web. Container, wie z.B. die Datenbank, die nicht von außen erreichbar sein sollen, können z.B. in ein Netzwerk backend gepackt werden. Wenn z.B. die App und die Datenbank im Netzwerk backend sind, können nur diese miteinander Daten austauschen. Aber nur die Anwendung mit der Datenbank.

docker network create web

Label link

Für das jeweilige Projekt sind von Traefik die Router, Middlewares und Services interessant. In Traffic können Router, Services und Middlewares wiederverwendet werden. Im Docker Ansatz finde ich das sehr unübersichtlich, daher verwende ich hier für jeden Container im Label einen eigenen Namen.

Es ist auch möglich mehrere Router, Middlewares oder Service Endpunkte für den Container zu definieren. Bei mir ist z.B. /metrics nur über einen speziellen Traefik Endpunkt erreichbar, der nicht global auf Port 80 hört und über eine interne Netzwerkkarte erreichbar ist. So kann nur mein Prometheus Server die Daten über das virtuelle Netzwerk abrufen.

Router und Service link

Die Router Label beschreiben, wann der Traffic in das Projekt geroutet wird. Die Router Rule kann viele verschiedene Parameter des Requests berücksichtigen und auch aus mehreren Kombinationen bestehen. Hier im Beispiel wird die verwendete Domain validiert. Es kann aber z.B. auch nach dem Präfix des Pfades geprüft werden.

Die Loadbalancer Anweisung definiert auf welchem Port der Container Traffic erwartet.

      - traefik.http.routers.my-container.rule=Host(`example.com`)
      - traefik.http.services.my-service.loadbalancer.server.port=12345