Docker-Windows-Container mit Ansible managen (1/2)
Vorwiegend im Java-Universum bekannte DevOps-Tools wie Ansible, Vagrant und Packer verwalten neuerdings auch Windows-Maschinen. Umgekehrt ermöglichen es Docker-Windows-Container, Spring-Boot-Anwendungen unter Windows laufen zu lassen.
- Jonas Hecht
Manchmal kann es sogar eingefleischten Java-Entwicklern passieren, dass sie ihre Anwendungen auf Windows laufen lassen müssen – zum Beispiel weil Legacy-Code oder native Visual-C-Bibliotheken einzubinden sind, die Windows voraussetzen. Wenn der erste Schreck verflogen ist, besinnt man sich schnell wieder auf wichtige Prinzipien moderner Softwareentwicklung wie Continuous Integration und Deployment (CI/CD) oder die Automatisierung sich wiederholender Aufgaben (Infrastucture as Code). Dazu sind CI-Server wie Jenkins nötig, die mit DevOps-Tools wie Ansible eine entsprechende Infrastruktur hochziehen. Und weil alle dazu benötigten Informationen im Versionskontrollsystem abgelegt sind, passiert das alles jederzeit vollständig für jeden im Team nachvollziehbar.
Auf derartige Annehmlichkeiten will man in der "Windows-Welt" ungern verzichten, was seit Kurzem auch nicht mehr nötig ist: Seit Version 1.7 unterstützt das aus der Unix-Welt bekannte Ansible das Management von Windows-Maschinen. Dazu kommt statt SSH natives PowerShell Remoting beziehungsweise das Windows Remote Management (WinRM) zum Einsatz. Zusätzlich bieten Windows 10 beziehungsweise Windows Server 2016 seit dem Anniversary-Update (ab Version 1607) die Möglichkeit, Docker-Container zu nutzen, die ihrerseits eine Windows-Umgebung bereitstellen – also nicht wie bisher gewohnt ausschließlich auf Linux basieren.
Aller Anfang ist ...
In aktuellen Softwareentwicklungsprojekten greifen Teams gern auf die Hilfe von Vagrant zurück. Mit einer einfachen Beschreibungssprache in einem sogenannten Vagrantfile und leicht erlernbaren Befehlen wie vagrant up sind schnell virtuelle Maschinen (VM) hochgefahren – inklusive entsprechender Tools und Konfiguration. Ist man üblicherweise im Linux/Unix-Umfeld zu Hause, ist einem die Vielfalt an Vagrant-Boxes (wie die vorkonfigurierten VMs auch genannt werden) der Vagrant Cloud vielleicht bekannt. Schwenkt man nun hinüber ins Microsoft-Universum, sieht es leider etwas anders aus. Immerhin bietet Microsoft mit der "Vagrant Box with Windows 10 from the Microsoft Edge developer" eine eigene offizielle Vagrant-Box an. Wer später Docker-Windows-Container ausführen will, sollte aktuell allerdings die Finger davon lassen. Ein Grund ist die Build-Nummer beziehungsweise das Datum der letzten Aktualisierung der genannten Vagrant-Box. Um Docker-Windows-Container betreiben zu können, benötigt man mindestens Version 10.0.14393.206. Hier entscheidet der vierte Ziffernblock! 10.0.14393.67 wie in der bereitgestellten Vagrant-Box ist in jedem Fall nicht ausreichend.
Um zu gewährleisten, dass alle Schritte vollständig nachvollziehbar bleiben und keine inoffziellen Vagrant-Boxes zum Einsatz kommen, deren Vertrauenswürdigkeit nur schwer nachprüfbar ist, gibt es nur eine Möglichkeit: eine eigene Vagrant-Box zu erstellen. Obwohl das im ersten Moment vielleicht einschüchtert, mit dem richtigen Werkzeug ist es kein großes Problem. Die Firma hinter Vagrant steht beim Bereitstellen der Boxes auf app.vagrantup.com vor der gleichen Herausforderung und hat deshalb mit Packer ein weiteres DevOps-Tool veröffentlicht, das ebenso wie Vagrant auf GitHub entwickelt wird und unter einer Open-Source-Lizenz jedem zur freien Nutzung verfügbar ist.
Packer ermöglicht es, aus einer ISO-Datei eine Vielzahl an Zielformaten zu erstellen – darunter die von AWS, Microsoft Azure, OpenStack, VMware und VirtualBox. Letztere lassen sich in einem Post-Processing-Schritt wiederum in Vagrant Boxes weiterverarbeiten. Das fehlende Puzzlestück ist dann nur noch ein geeignetes ISO-Abbild als Basis für den Packer-Build. Und hier kommen die Evaluation-ISOs des Windows Server 2016 beziehungsweise von Windows 10 Enterprise gerade richtig. Beide bieten eine 180-tägige Evaluierungslizenz, die nach einer Registrierung automatisch in das ISO-Image eingebracht wird.
Windows 10 oder Server 2016?
An dieser Stelle ein Hinweis bezĂĽglich der fĂĽr Docker-Windows-Container aktuell zu empfehlenden Windows-Version: Wie im Artikel "Windows- und Linux-basierte Docker-Container auf Windows nutzen" dargestellt, gibt es zwei Arten von Windows-Containern: Windows-Server-Container mit dem sogenannten Isolation Level "process" und einem gemeinsam genutzten Windows-Kernel sowie Hyper-V-Container mit Isolation Level "hyper-v", die sich eines Hypervisors bedienen und mehr Isolation bieten.
Windows 10 unterstützt dabei ausschließlich Hyper-V-Container. Sie sind weiter von der bekannten Docker-Philosophie entfernt, eben gerade auf einen Hypervisor zu verzichten und die Ressourcen einer Maschine optimal allen Containern zur Verfügung stellen zu können. Auch wenn es vielleicht im ersten Moment so scheint, als sei der Einstieg in das Thema mit Windows 10 leichter zu meistern, ist gerade für professionelle Entwicklungsvorhaben aktuell davon abzuraten.
Da der Windows Docker Host in den meisten Fällen virtualisiert zum Einsatz kommt, lässt sich nur mit Windows 10 oder Windows Server 2016 auf einen zweiten Hypervisor verzichten. Ein im Kundenprojekt betriebener Windows-Docker-Host in VMware ESXi konnte reibungslos mit Windows Server 2016 betrieben werden, wohingegen Windows 10 nicht zu einem sauberen Docker-Betrieb zu überreden war. Obwohl sich die weiteren Schritte für beide Windows-Versionen gleichermaßen nutzen lassen, ist eine klare Empfehlung für Windows Server 2016 in produktiv genutzten Umgebungen auszusprechen.
Packer baut eine Windows-Vagrant-Box
Um das Beispiel des vorliegenden Artikels vollständig nachvollziehbar zu gestalten, liegen alle dafür notwendigen Quellen in einem GitHub-Projekt bereit. Es enthält mehrere aufeinander aufbauende Schritte, die im Verlauf des Artikels näher erläutert werden. Alles für das Erstellen einer Windows-Vagrant-Box mit Packer Nötige findet sich im Verzeichnis step0-packer-windows-vagrantbox.
Bevor mit dem Schritt begonnen wird, sollten VirtualBox, Vagrant, Packer und Git in der aktuellen Version installiert sein. Am einfachsten funktioniert das ĂĽber ein Paketmanagementsystem wie Homebrew fĂĽr den Mac (z.B. per brew install packer) oder chocolatey fĂĽr Windows. In einem Linuxsystem verwendet man einfach den jeweils mitgelieferten Paktetmanager. AuĂźerdem empfiehlt sich der Download einer ISO-Abbilddatei von Windows Server 2016. Liegt dann noch das GitHub-Repository lokal vor, kann es losgehen. Auf einer Kommandozeile wechselt man in das Verzeichnis step0-packer-windows-vagrantbox und startet den Packer-Build mit dem folgenden Befehl (Pfeile weisen im Folgenden auf dem Layout geschuldete ZeilenumbrĂĽche hin):
packer build -var iso_url=14393.0.161119-1705.RS1_REFRESH_SERVER_EVAL_↵
X64FRE_EN-US.ISO -var iso_checksum=70721288bbcdfe3239d8f8c0fae55f1f ↵
windows_server_2016_docker.json
Idealerweise liegt die Windows-Server-Abbilddatei im selben Verzeichnis. Der Befehl übergibt Packer den Ort des ISOs, die entsprechende Checksumme und die Konfigurationsdatei, mit der sich der Packer-Build beeinflussen lässt. Der Windows-Installationsprozess dauert eine Weile, ist jedoch vollständig automatisiert, sodass keine einzelne Benutzerinteraktion notwendig ist. Die "Unattended Installation" installiert Windows Server 2016 in eine virtuelle Maschine (siehe Abb. 1).
Die Konfigurationsdatei von Packer gibt Aufschluss darüber, wie der Vorgang abläuft. Im konkreten Beispiel beginnt die Datei windows_server_2016_docker.json mit der Packer-Builder-Konfiguration:
"builders": [
{
"vm_name":"WindowsServer2016Docker",
"type": "virtualbox-iso",
"communicator": "winrm",
...
Außer dem Namen der virtuellen Maschine können Entwickler mit dem Schlüsselwort type definieren, dass das Ergebnis ein VirtualBox-Image sein soll. Zur Kommunikation wird statt des im Linux-Umfeld üblichen SSH wie erwähnt WinRM beziehungsweise natives PowerShell Remoting eingesetzt. Im Detail ergeben sich noch ein paar weitere Konfigurationsparameter, die etwa das Nutzerkonto, den Betriebssystemtyp oder die Hardwareausstattung der virtuellen Maschine festlegen. In der folgenden "Provisioners Section" ist die Ausführung eines wichtigen Skripts konfiguriert. Die Ansible-Entwickler stellen das Ansible PowerShell Configuration Script direkt bereit und ermöglichen so das Einrichten der Netzwerkeinstellungen und Firewall-Regeln für die erfolgreiche Verbindung per WinRM.
Im Beispiel schafft ein vorgelagerter Schritt im Packer-Build nahezu alle Voraussetzungen: Die Datei Autounattend.xml konfiguriert außer der komplett automatisierten Windows-Installation jene Netzwerkeinstellungen für WinRM, die Ansible nachher benötigt. Unter anderem sind in ihr die Windows-Version und der Nutzer vagrant festgelegt, der in allen Folgeschritten zur Anmeldung in Windows Verwendung findet. Diese Art XML-Dateien lässt sich mit dem Windows Assessment and Deployment Kit (Windows ADK) erzeugen. Hierfür ist allerdings zwingend eine Windows-Installation erforderlich. Das Beispiel-Repository liefert eine vollständig nutzbare Variante, sodass man sich damit nur im Ausnahmefall beschäftigen muss.