Docker Compose vs. Docker Swarm: verwenden und verstehen
Mit Docker Swarm können Nodes (Hosts) zu einem gemeinsamen Verbund zusammengefasst werden. Dies ermöglicht es Container in einer beliebigen Anzahl von Instanzen auf einer beliebigen Anzahl von Knoten (Hosts) im Netzwerk zu betrieben. Die Basis für die Kommunikation zwischen den Hosts bildet in Docker Swarm ein Overlay-Netzwerk für die Services: Multi-host networking. Wie in meinem Artikel zum Webserverumzug bereits angedeutet, habe ich Docker Swarm als mögliche Option für ein gemeinsames hostübergreifendes Netzwerk getestet und dazu einige Erkenntnisse gesammelt, die ich hier kurz zusammenfasse.
Swarm Netzwerk
Docker Swarm stellt für alle Nodes ein gemeinsames Backend-Netzwerk zur Verfügung, wodurch es keine Rolle spielt, auf welchem Node die Container betreiben werden. Als Beispiel könnte ein Webfrontend auf einem Host laufen, dessen Datenbank auf einem anderen. Das Webfrontend kann die Datenbank über das Overlay-Netzwerk erreichen, als ob sich diese am selben Host befinden würde. Auch der Netzwerkzugriff auf die Container könnte über alle Host-IP-Adressen der Nodes stattfinden, auch über einen Host auf dem sich der Container gar nicht befindet.
Docker Volumes und Swarm
Für das permanente Speichern von Container-Daten werden bekanntlich Docker Volumes oder Bind-Mounts eingesetzt. Docker-Swarm kümmert sich zwar um das Netzwerk, zunächst aber nicht um den Datenspeicher: Jeder Host speichert seine eigenen Daten.
Zurück zum Beispiel mit der Datenbank und beim Einsatz von Docker-Volumes ohne Volume-Treiber oder zentralem Speicher. Wird ein Container, nachdem er bereits Daten in ein Volume geschrieben hat auf einem anderen Host deployt, sind die Daten der Volumes dort nicht verfügbar, ganz als ob der Container das erste Mal gestartet wird. Für Services die keine persistenten Daten haben mag das egal sein, nicht aber beim Einsatz von Volumes. Um Volumes auf allen Swarm-Nodes zur Verfügung stellen zu können, können entsprechende Volume-Treiber, eine Shared Storage oder NAS eingesetzt werden. Auch ein permanentes Synchronisieren der Ordner mit einer zusätzlichen Software, als Beispiel mit GlusterFS wäre denkbar.
Was ist der Unterschied zwischen Docker Swarm und Docker Compose?
Die Art und Weise, wie Anwendung mit Docker Swarm oder Docker-Compose bereitgestellt werden, ist sehr ähnlich. Der Unterschied liegt vor allem im Backend: Während docker-compose die Container auf einem einzigen Docker-Host bereitstellt, verteilt Docker Swarm sie auf mehrere Nodes. Die Anwendung wird in beiden Fällen in einer YAML-Datei definiert. Diese Datei enthält den Image-Namen, die Konfiguration für jedes Image und für Docker Swarm auch die Anzahl der bereitgestellten Container.
Test-Setup mit Ubuntu-Server
Als Vorbereitung habe ich Ubuntu-Server installiert, siehe: Ubuntu Server installieren
Auf dem Server wird ein Docker-Setup vorausgesetzt, siehe: Docker.
Docker Swarm initialisieren
Um aus einer normalen Docker-Installation eine Swarm-Umbebung zu machen, reicht ein einfacher Befehl: "docker swarm init"
me@l1:~$ docker swarm init --advertise-addr 192.168.1.176
Swarm initialized: current node (hbjltjuhvsy0ctdogqj37gqt6) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-3ckd3o0uz1qnhe6uigk5wjosx5ugttqm8in9p2v691mje8063z-5p85da80dx8ngyop26t4cjkam 192.168.1.176:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Beim Initialisieren wird der Befehl ausgegeben, um weitere Worker-Nodes zum Swarm hinzuzufügen. Weitere Hosts können nach der Docker-Installation mit docker swarm join zum Swarm-Verbund hinzugefügt werden:
me@l2:~$ docker swarm join --token SWMTKN-1-433lfak5cy35idwysc7gslpne8vsuyjzvwdc2e48eo63qyb5mm-1osbaa8c497s6ms8x2ggn70xu 192.168.1.176:2377
[sudo] password for me:
This node joined a swarm as a worker.
Wer bereits einen Docker-Swarm initialisiert hat und nochmal von neuem starten will, kann das Erstellen eines neuen Clusters erzwingen, indem als Option: --force-new-cluster mitgegeben wird:
docker swarm init --force-new-cluster
Docker-compose command vs. Swarm stack deploy
Docker-Compose wird bekanntlich dazu verwendet verschiedene Container für eine Applikation zu starten: Services. Als Beispiel kann in einer docker-compose.yml ein Webservice und dessen Datenbank beschrieben werden. Zudem kann in der docker-compose.yml-Datei der Zugriff zwischen den Containern einer Applikation und der Zugriff von außen auf die Container vorgegeben werden. Alle beschriebenen Container können mit einem Befehl als Einheit heruntergeladen, gestartet oder gestoppt werden. Wird der Befehl "docker compose up" aus dem Ordner mit der docker-compose.yml-Datei aufgerufen, werden die Images für alle erwähnten Services heruntergeladen und diese gestartet.
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Beim Einsatz von Swarm wird anstelle des Befehls "docker-compose", "docker stack deploy" verwendet. Zusätzlich zum Einsatz mit docker-compose können bei einem stack deploy auch noch Optionen zur Anzahl der Instanzen und deren Replikate mitgegeben werden. Im Gegenzug besitzt Docker Compose ohne Swarm bestimmte Eigenschaften die in Docker Swarm und dessen stack deploy unnötig sind oder nicht unterstützt werden.
Der Wechsel von Docker-Compose zu Docker Swarm
Wer bisher Docker Compose ohne Swarm eingesetzt hat und auf Docker Swarm wechselt, muss die docker-compose.yml-Dateien eventuell etwas anpassen. Hier die Optionen die mir beim Wechsel untergekommen sind:
Restart und expose entfernen
Wer eine docker-compose-Datei im Swarm-Modus mit docker stack deplay verwendet, wird auf Optionen hingewiesen, die mit Swarm nicht verwendet werden können oder sollen:
Ignoring unsupported options: restart
Ignoring deprecated options:
expose: Exposing ports is unnecessary - services on the same network can access each other's containers on any port.
Entsprechend sollten die Option "restart" und "expose" beim Einsatz von Swarm aus der docker-compose.yml-Datei entfernt werden:
#restart: always
#expose:
Option Container_name wird nicht unterstützt
Ignoring deprecated options:
container_name: Setting the container name is not supported.
Mit Docker Compose ohne Swarm gibt es mit der Option "container_name" die Möglichkeit jedem Container einen Namen zu geben. Docker Swarm setzt den Namen aus dem Service und einer Option die beim Start von docker stack deploy mitgegeben wird zusammen. Der Name sollte für den Einsatz mit Swarm aus der docker-compose.yml-Datei entfernt werden:
container_name enfernen:
services:
web:
#container_name: libenet_web
Der Name wird beim Start des Stack mitgeben:
docker stack deploy -c docker-compose.yaml stackname
Docker Swarm bildet aus dem Service, im Beispiel "web:" und dem Stack-Namen den Containernamen.
stackname_ wird zum Service hinzugefügt.
Der finale Containername wäre für dieses Beispiel: "stackname_web"
Docker Stack mit Dockerfile verwenden
Für mein Webservice habe ich in Docker Compose bisher die Option "build" verwendet, welche beim Starten mittels "docker compose up" ein eigenes Images auf basis eines Dockerfile erstellt hat:
version: '3'
services:
web:
container_name: laravel_web
build:
context: .
dockerfile: Dockerfile
Siehe: mein Docker-Webserver Setup für Laravel - Konfig im Detail.
Die "build:"-Option ist mit Docker-Stack nicht mehr verfügbar:
You need to create the image with docker build (on the folder where the Dockerfile is located):
Die Images müssen vor dem Einsatz von Docker Swarm erzeugt werden und in der lokalen oder einer Remote-Registry zur Verfügung stehen:
docker build -t imagename
Nach dem Ausführen des Build-Befehls ist das Image (mit dem Namen imagename) in der lokalen Registry verfügbar, wodurch es in der Docker-Compose-Datei wie folgt verwendet werden kann:
version: '3'
services:
example-service:
image: imagename:latest
...
Docker Swarm verschlüsseltes Ingress Netzwerk auf Webservern im Internet?
Die Daten der Verwaltungs- und Steuerungsebene von Swarm sind immer verschlüsselt, nicht aber die Anwendungsdaten zwischen den Swarm-Nodes.
ⓘAnwendungsdaten zwischen Swarm-Nodes werden standardmäßig nicht verschlüsselt. Um diesen Datenverkehr in einem bestimmten Overlay-Netzwerk zu verschlüsseln, verwenden Sie das Flag --opt encrypted bei docker network create. Dies aktiviert die IPSEC-Verschlüsselung auf der Ebene des vxlan. Diese Verschlüsselung hat einen nicht zu vernachlässigenden Leistungsverlust zur Folge, daher sollten Sie diese Option testen, bevor Sie sie in der Produktion einsetzen. siehe: https://docs.docker.com/engine/swarm/networking/ (Datum: 28.09.2022)
Wer Docker-Swarm für Server die sich im Internet befinden einsetzt, sollte ein privates Netzwerk für die Kommunikation der Server untereinander verwenden. Bestimmte Cloud-Provider bieten dazu eine Möglichkeit ein privates Netz zwischen den Servern zu erstellen:
Standardmäßig erlaubt Swarm auf allen Adressen eine Verbindung für das Swarm-Backend. Um den Netzwerkverkehr auf das interne Netzwerk zu limitieren, kann die Option --listen-addr mitgegeben werden. Hier als Beispiel der Befehl für das Initialisieren eines Docker Swarm mit einer öffentlichen und einer privaten Adresse:
docker swarm init --advertise-addr PublicIP --listen-addr PrivateIP:2377
Ist das Netzwerk zwischen den Hosts nicht vertrauenswürdig, kann auch der Datenverkehr für die Anwendungsdaten verschlüsselt werden. Die Verschlüsselung für ein bestimmtes Netzwerk kann mit folgendem Befehl aktiviert werden:
docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network
Fazit
Docker Swarm bietet eine einfache Möglichkeit das Docker-Setup auf mehrere Hosts zu verteilen. Für den sinnvollen Betrieb wird allerdings ein zentraler Speicher für die Volumes benötigt. Siehe auch: Webserver mit Docker Container umziehen, Theorie und Praxis. Eventuell auch interessant: Docker Swarm, Portainer und Traefik kombiniert
{{percentage}} % positiv