Docker Swarm: Der unterschätzte Orchestrator

Ein einfacherer Start, bevor man in Kubernetes einsteigt.

Docker Swarm: Der unterschätzte Orchestrator

Docker Swarm Mode wird oft als veraltet abgetan, insbesondere im Schatten des Giganten Kubernetes. Diese Annahme basiert jedoch häufig auf einer Verwechslung mit dem tatsächlich nicht mehr aktiv entwickelten “Classic Swarm”. Der direkt in die Docker Engine integrierte Swarm Mode ist hingegen eine schlanke, aber äußerst leistungsfähige Lösung zur Orchestrierung von Containern, die eine ideale Balance zwischen einfacher Handhabung und fortgeschrittenen Cluster-Funktionen bietet. Er verwandelt eine Gruppe von Docker-Hosts in einen einzigen, virtuellen Host und ermöglicht so Hochverfügbarkeit, Lastausgleich und ein zentrales Management, ohne die steile Lernkurve von Kubernetes zu erfordern.

Docker Swarm Mode: Mehr als nur ein Relikt

Der entscheidende Vorteil des Swarm Mode liegt in seiner nahtlosen Integration in die bekannte Docker-Umgebung. Anstatt ein komplett neues Ökosystem erlernen zu müssen, können bestehende Werkzeuge und Kenntnisse, insbesondere im Umgang mit docker compose, weitgehend wiederverwendet werden. Swarm Mode erweitert die Docker Engine um native Cluster-Management-Funktionen.

Dazu gehören unter anderem:

  • Zentralisiertes Cluster-Management: Verwaltung mehrerer Docker-Nodes als eine einzige Einheit.
  • Deklarative Service-Modelle: Definition des gewünschten Zustands einer Anwendung, den der Swarm dann automatisch herstellt und aufrechterhält.
  • Skalierung: Einfaches Hoch- und Herunterskalieren der Anzahl von Containern für einen bestimmten Service.
  • Selbstheilung: Der Scheduler startet Container auf einem gesunden Node neu, falls der ursprüngliche Node ausfällt.
  • Rolling Updates: Aktualisierungen von Services werden schrittweise und ohne Ausfallzeit durchgeführt.
  • Sichere Kommunikation: Die Kommunikation zwischen den Nodes wird standardmäßig durch mutuelle TLS-Verschlüsselung (mTLS) abgesichert.

Die Architektur: Manager, Worker und das Quorum

Ein Docker Swarm besteht aus zwei Arten von Nodes: Manager und Worker.

  • Manager-Nodes sind für die Steuerung und Verwaltung des Clusters zuständig. Sie treffen Entscheidungen über die Platzierung von Containern (Scheduling), verwalten den Cluster-Zustand und beantworten API-Anfragen.
  • Worker-Nodes haben nur eine Aufgabe: Sie führen die Container (hier Tasks genannt) aus, die ihnen von den Managern zugewiesen werden.

Für Hochverfügbarkeit ist die Anzahl der Manager entscheidend. Ein Swarm-Cluster benötigt eine ungerade Anzahl von Managern (z. B. 1, 3, 5), um ein Quorum aufrechtzuerhalten. Das bedeutet, mehr als die Hälfte der Manager muss online sein, damit der Cluster funktionsfähig bleibt. Fällt der Leader-Manager aus, wird aus den verbleibenden Managern automatisch ein neuer Leader gewählt. Ein Cluster mit nur einem Manager ist somit funktionsfähig, aber nicht hochverfügbar.

Aufbau eines Swarm-Clusters: In drei Schritten zum Ziel

Die Einrichtung eines Swarm-Clusters ist erstaunlich unkompliziert. Voraussetzung sind lediglich mehrere Linux-Systeme, auf denen die Docker Engine installiert ist. Für dieses Beispiel werden drei virtuelle Maschinen verwendet: vm-test-1 (10.20.30.1), vm-test-2 (10.20.30.2) und vm-test-3 (10.20.30.3).

1. Initialisierung des Swarms

Auf dem ersten Node, der zum Leader des Clusters werden soll (vm-test-1), wird der Swarm initialisiert. Der Parameter --advertise-addr gibt an, unter welcher IP-Adresse die anderen Nodes diesen Manager erreichen können.

Die Ausgabe dieses Befehls ist von zentraler Bedeutung. Sie enthält den Befehl inklusive eines Join-Tokens, mit dem sich weitere Nodes als Worker dem Cluster anschließen können.

2. Hinzufügen von Worker-Nodes

Der zuvor ausgegebene Befehl wird nun auf den beiden anderen Maschinen (vm-test-2 und vm-test-3) ausgeführt, um sie dem Cluster als Worker hinzuzufügen.

Nachdem alle Nodes beigetreten sind, kann der Status des Clusters auf dem Manager-Node überprüft werden:

Die Ausgabe zeigt alle drei Nodes, wobei vm-test-1 der Leader und die anderen beiden einfache Worker sind.

3. Hochstufen von Workern zu Managern

Um Hochverfügbarkeit zu gewährleisten, werden die beiden Worker nun ebenfalls zu Managern hochgestuft. Dieser Befehl muss vom aktuellen Leader aus ausgeführt werden.

# Auf vm-test-1 ausführen
docker node promote vm-test-2
docker node promote vm-test-3

Eine erneute Überprüfung mit docker node ls zeigt, dass nun alle drei Nodes den Manager-Status “Reachable” haben. Fällt vm-test-1 aus, wird einer der beiden anderen die Leader-Rolle übernehmen.

Vom Container zum Service: Die neue Art der Ausführung

Im Swarm Mode werden Container nicht mehr einzeln mit docker run gestartet, sondern als Services deklariert. Ein Service definiert, welches Image verwendet werden soll, wie viele Replikate (Instanzen) laufen sollen und welche Ports veröffentlicht werden.

Ein nginx-Service mit zwei Replikaten, der auf Port 8081 erreichbar ist, wird wie folgt erstellt:

Mit docker service ls kann der Status des Services eingesehen werden.

Um herauszufinden, auf welchen Nodes die einzelnen Container (Tasks) laufen, dient der Befehl docker service ps.

Der Swarm-Scheduler hat die beiden Container intelligent auf vm-test-1 und vm-test-2 verteilt. Führt man docker ps auf einem der Nodes aus, sieht man nur den Container, der auf diesem spezifischen Host läuft.

Der Befehl docker ps agiert also weiterhin auf Ebene der einzelnen Docker Engine, nicht auf der des gesamten Clusters.

Die Selbstheilungsfunktion kann leicht demonstriert werden. Wird einer der Nginx-Container manuell gestoppt, erkennt der Swarm dies und startet sofort einen neuen Task auf einem verfügbaren Node, um den gewünschten Zustand von zwei Replikaten wiederherzustellen.

Das Routing Mesh: Integriertes Load Balancing

Eine der beeindruckendsten Funktionen des Swarm Mode ist das eingebaute Ingress Routing Mesh. Wenn ein Port für einen Service veröffentlicht wird (wie Port 8081 in unserem Beispiel), wird dieser Port auf allen Nodes des Clusters geöffnet, unabhängig davon, ob auf diesem Node gerade ein Container des Services läuft oder nicht.

Eine Anfrage an http://10.20.30.3:8081 (die IP von vm-test-3, auf dem kein Nginx-Container läuft) wird vom Swarm automatisch und per Lastausgleich an einen der laufenden Container auf vm-test-1 oder vm-test-2 weitergeleitet.

Dies vereinfacht das Service-Discovery und den Lastausgleich erheblich, da keine externen Load Balancer wie MetalLB (im Kubernetes-Umfeld) benötigt werden. Jede Anfrage an einen beliebigen Node des Clusters auf dem veröffentlichten Port erreicht den Service.

Die Königsklasse: Von docker compose zu docker stack

Die wahre Stärke des Swarm Mode entfaltet sich in der Verwendung von docker-compose-Dateien. Anstatt Services manuell über die Kommandozeile zu erstellen, können sie in compose.yml-Dateien definiert und als Stack deployed werden. Dies ermöglicht deklarative, versionierbare und wiederverwendbare Anwendungsdefinitionen.

Die Syntax ist dabei weitgehend identisch mit der von docker-compose, mit einigen wichtigen Anpassungen.

  • container_name: Wird nicht unterstützt, da der Swarm die Namen der Tasks dynamisch vergibt.
  • restart: Wird durch die deploy-Sektion des Swarms ersetzt, die eine eigene Restart-Policy hat.
  • deploy Sektion: Dies ist die zentrale Erweiterung für den Swarm Mode. Hier werden Replikate, Platzierungs-Constraints, Update-Konfigurationen und Ressourcen-Limits definiert.

Eine compose.yml für einen Nginx-Stack könnte wie folgt aussehen:

# compose.yml
version: '3.8'

services:
  nginx:
    image: nginx:latest
    ports:
      - "8081:80"
    deploy:
      replicas: 3
      placement:
        constraints:
          # Container nur auf Workern und Managern ausführen, die nicht vm-test-1 heißen
          - node.hostname != vm-test-1
      restart_policy:
        condition: on-failure

Anstelle von docker-compose up wird der Stack mit dem Befehl docker stack deploy ausgerollt:

docker stack deploy -c compose.yml nginx-stack-2

Der Befehl erstellt alle notwendigen Ressourcen (Services, Netzwerke etc.) im Cluster.

Bestehende Standalone-Container oder docker-compose-Projekte auf den Hosts werden davon nicht berührt. Man kann also schrittweise und service-weise von einer Standalone-Umgebung in den Swarm Mode migrieren.

Sicheres Management: Secrets und Configs im Schwarm

Ein weiteres mächtiges Feature sind docker secret und docker config. Anstatt sensible Daten wie Passwörter oder Konfigurationsdateien in Images einzubacken oder ungesichert auf dem Host-Dateisystem zu lagern, können sie zentral und sicher in der verschlüsselten Datenbank des Swarms verwaltet werden.

Secrets sind ideal für Passwörter, API-Keys oder TLS-Zertifikate. Sie werden im Cluster erstellt und dann gezielt den Services zugewiesen, die sie benötigen.

# Ein Secret erstellen
echo "MeinSuperGeheimesPasswort123" | docker secret create db_password -

Configs funktionieren analog für Konfigurationsdateien.

# Eine Konfigurationsdatei erstellen
docker config create nginx_config /pfad/zur/nginx.conf

In der compose.yml werden diese dann referenziert. Der Swarm mountet Secrets standardmäßig als Datei unter /run/secrets/<secret_name> im Container.

# compose.yml
version: '3.8'

services:
  my-app:
    image: my-app:latest
    secrets:
      - db_password
    configs:
      - source: nginx_config
        target: /etc/nginx/nginx.conf

secrets:
  db_password:
    external: true

configs:
  nginx_config:
    external: true

Wichtig ist hierbei, dass viele Anwendungen erwarten, Passwörter als Umgebungsvariable zu erhalten. Da Secrets als Dateien gemountet werden, müssen die verwendeten Container-Images in der Lage sein, Secrets aus einer Datei zu lesen (oft durch eine _FILE-Endung in der Umgebungsvariablen wie DB_PASSWORD_FILE).

Herausforderungen und Lösungen: Persistenter Speicher und Netzwerke

Trotz aller Eleganz gibt es zwei Bereiche, die besondere Aufmerksamkeit erfordern:

  1. Persistenter Speicher: Standardmäßig sind Docker Volumes lokal auf dem jeweiligen Node. Fällt ein Node aus und ein stateful Service (z.B. eine Datenbank) wird auf einem anderen Node neu gestartet, hat dieser keinen Zugriff auf die alten Daten. Eine praktikable Lösung, die bereits in einem früheren Artikel über Docker-Volumes auf einem NFS-Server behandelt wurde, ist die Nutzung eines zentralen Netzwerkspeichers. Alternativ unterstützt Swarm Storage-Treiber für verteilte Dateisysteme wie Ceph, was jedoch eine höhere Komplexität mit sich bringt.
  2. Netzwerke: Der Swarm Mode führt den Overlay-Netzwerktreiber ein. Overlay-Netzwerke erstrecken sich über alle Nodes des Clusters und ermöglichen eine nahtlose Kommunikation zwischen Containern, egal auf welchem Host sie laufen. Mit dem --attachable-Flag können sogar Standalone-Container (die nicht als Service laufen) mit diesen clusterweiten Netzwerken verbunden werden, was eine flexible Migration und hybride Setups ermöglicht.

Fazit

Docker Swarm Mode ist eine ausgereifte und stabile Lösung für die Container-Orchestrierung, die sich durch ihre Einfachheit und Integration in das Docker-Ökosystem auszeichnet. Er bietet die wichtigsten Funktionen wie Hochverfügbarkeit, Skalierbarkeit und Rolling Updates, ohne den administrativen Aufwand von Kubernetes zu erfordern. Für Home-Labs, kleine bis mittlere Projekte oder Teams, die bereits mit docker-compose vertraut sind, stellt Swarm Mode einen logischen und äußerst effizienten nächsten Schritt dar.