Die hybride Cloud mit Docker Swarm und Ansible (2/2)

Nachdem die hybride Cloud aus Windows- und Linux-Systemen dank Packer und Vagrant zur Verfügung steht, soll Ansible jetzt einen Docker Swarm automatisiert initialisieren und das Deployment vorbereiten.

Know-how  –  9 Kommentare
Die hybride Cloud mit Docker Swarm und Ansible, Teil 2

Im ersten Teil der Artikelserie ist die "Cloud in der Hosentasche" mit Packer und Vagrant so aufgebaut worden, dass alle Kombinationen aus Windows- und Linux-Maschinen in einer hybriden Cloud lokal für weitere Schritte zur Verfügung stehen. Darauf aufbauend zeigt dieser Artikel, wie Ansible einen Docker Swarm vollautomatisiert initialisiert und das spätere Applikations-Deployment vorbereitet.

Bevor Ansible Maschinen provisionieren kann, müssen sie zur Verfügung stehen und für die Verbindung per SSH oder WinRM vorbereitet sein. Mit den "Infrastructure-as-Code"-Werkzeugen Packer und Vagrant kann auch dieser Schritt automatisiert ablaufen. Sobald sich das Projekt mehr in Richtung Produktion bewegt, ist der Einsatz von zum Beispiel Terraform ebenfalls denkbar. Es stehen mehrere virtuelle Maschinen zur Verfügung, benannt nach ihrer späteren Verwendung im Docker Swarm. Nun kann Ansible das Zepter übernehmen.

Um einen Docker Swarm so bereitzustellen, dass danach alles für ein Applikations-Deployment bereitsteht, sind einige Schritte notwendig. Zuerst sollte Docker auf allen Cluster-Nodes installiert und konfiguriert sein. Dann ist die Initalisierung eines Docker Swarm möglich. Außerdem sollte man nicht vergessen, eine Docker Swarm Registry zu konfigurieren und als Docker Swarm Service zu starten. Denn über den Service läuft später die Bereitstellung der Docker-Images der Applikationen auf alle Cluster-Nodes. Nicht zuletzt darf eine Managementoberfläche für den einfachen Überblick über alle Docker-Nodes und den Swarm als Ganzes nicht fehlen.

Alle beschriebenen Schritte sind wieder vollständig nachvollziehbar im Beispiel-GitHub-Projekt verfügbar. Dort findet sich das Verzeichnis step4-windows-linux-multimachine-vagrant-docker-swarm-setup, das wiederum das Ansible-Playbook prepare-docker-nodes.yml enthält. Ist die Abstrahierung der Details in den Playbooks sauber, kann praktisch jedes (Scrum-)Teammitglied sie lesen (und verstehen):

- hosts: all

tasks:
- name: Checking Ansible connectivity to Windows nodes
win_ping:
when: inventory_hostname in groups['windows']

- name: Checking Ansible connectivity to Linux nodes
ping:
when: inventory_hostname in groups['linux']
- name: Allow Ping requests on Windows nodes (which is by default disabled in Windows Server 2016)
win_shell: "netsh advfirewall firewall add rule name='ICMP Allow incoming V4 echo request' protocol=icmpv4:8,any
when: inventory_hostname in groups['windows']

- name: Prepare Docker on Windows nodes
include: "../step1-prepare-docker-windows/prepare-docker-windows.yml host=windows"

- name: Prepare Docker on Linux nodes
include: prepare-docker-linux.yml host=linux

- name: Allow local http Docker registry
include: allow-http-docker-registry.yml

Aufgrund der Abstraktion der Details der Provisionierung gibt es das Phänomen, dass es keine besseren How-to-Beschreibungen als Ansible-Playbooks gibt. Die notwendigen Befehle sind in Form eines Blog-Posts nacheinander aufgelistet – mit dem Unterschied, dass ein Ansible-Playbook ausführbar ist. Damit ist nachgewiesen, dass das im Playbook beschriebene Verfahren funktioniert.

Mit dem Befehl ansible-playbook -i hostsfile prepare-docker-nodes.yml ist das vorliegende Playbook einfach im Verzeichnis step4-windows-linux-multimachine-vagrant-docker-swarm-setup ausführbar. Während der Ausführung steht genug Zeit zur Verfügung, sich mit den Details des Skripts vertraut zu machen. Bereits die erste Zeile ist dabei beachtenswert. Die Anweisung hosts: all beauftragt Ansible, alle zur Verfügung stehenden Maschinen parallel zu provisionieren. Das heißt, dass die Skriptausführung praktisch gleichzeitig auf den Cluster-Nodes masterlinux01 , masterwindows01 , workerlinux01 und workerwindows01 läuft.

Die folgenden zwei tasks stellen eine Empfehlung beim Umgang mit Ansible dar – besonders in hybriden Umgebungen. Zuerst sollte immer eine Prüfung der Verbindung stehen. Nur, wenn Ansible auf alle Maschinen Zugriff hat, sollte man die Skriptausführung fortsetzen.

Alle Cluster-Nodes sind für Ansible erreichbar

Erste Schritte zeigen eine wichtige Erkenntnis mit Ansible im Umgang mit hybriden Clustern auf. Da die meisten Ansible-Module strikt nach Linux und Windows getrennt und zueinander inkompatibel sind, muss immer sichergestellt sein, welche Art von Maschine man gerade aufrufen möchte. Die sogenannten Ansible conditionals und die Anweisung when können hierbei helfen. Die folgende Bedingung stellt sicher, dass das definierte Ansible-Modul sich ausschließlich auf einem Host der Gruppe linux ausführen lässt:

 when: inventory_hostname in groups['linux']

Damit findet das Modul nur auf den Hosts masterlinux01 und workerlinux01 Anwendung und es ignoriert die Windows-Hosts masterwindows01 und workerwindows01. Entsprechend funktioniert das auch genau entgegengesetzt:

when: inventory_hostname in groups['windows'] 

Im Ansible-Playbook prepare-docker-nodes.yml folgt auf die Verbindungstests ein Windows-exklusiver task. Denn Windows Server 2016 blockiert im Auslieferungszustand den ping. Damit das im späteren Verlauf nicht zu Problemen führt, steht ein Powershell-Kommando bereit, das mit Ansible-Moduls win_shell ausführbar ist:

- name: Allow Ping requests on Windows nodes (which is by default disabled in Windows Server 2016)
win_shell: "netsh advfirewall firewall add rule name='ICMP Allow incoming V4 echo request' protocol=icmpv4:8,any
when: inventory_hostname in groups['windows']

Mit den nachfolgenden tasks folgt eine Docker-Installation auf allen Cluster-Nodes. Glücklicherweise können Entwickler wieder auf den letzten Artikel "Docker-Windows-Container mit Ansible managen" aufbauen. Der Artikel beschreibt im Detail, wie die Installation und Konfiguration der aktuellen Inkarnationsstufe von Docker unter Windows (auch "Docker native" genannt) per Ansible funktioniert. Das entsprechende Playbook kann einfach Wiederverwendung finden. Nur die Anweisung host=windows benötigt eine Konfiguration, damit das Skript im aktuellen Kontext funktioniert:

- name: Prepare Docker on Windows nodes 
include:"../step1-prepare-docker-windows/prepare-docker-windows.yml
host=windows"

Genau den Anweisungen des offiziellen "Get Docker CE for Ubuntu"-Guide zufolge funktioniert die Bereitstellung von Docker auf den Ubuntu-Nodes. Das aufgerufene Playbook prepare-docker-linux.yml schließt wiederum mit der Anweisung host=linux ab, damit nur die Linux-Nodes nach diesem Verfahren mit Docker bestückt sind.

- name: Prepare Docker on Linux nodes 
include: prepare-docker-linux.yml host=linux

Falls jetzt eine andere Linux-Distribution zum Einsatz kommen soll, sind die jeweiligen Anweisungen im inkludierten Playbook prepare-docker-linux.yml anzupassen oder eine entsprechende Ansible-Rolle aus der Ansible Galaxy zu nutzen.