Docker-Windows-Container mit Ansible managen (2/2)

Nachdem im ersten Teil der Fokus auf dem automatisierten Erstellen einer Windows-Vagrant-Box mit Packer samt Installation von Docker lag, soll es nun um die Provisionierung von Spring-Boot-Anwendungen per Ansible gehen.

In Pocket speichern vorlesen Druckansicht
Docker-Windows-Container mit Ansible managen (2/2)
Lesezeit: 14 Min.
Von
  • Jonas Hecht
Inhaltsverzeichnis

Um Spring-Boot-Anwendungen in Docker-Windows-Containern laufen zu lassen, sollte Docker auf dem System bereitstehen und der Zugriff für Ansible entsprechend eingerichtet sein. Durch das Verwenden der Windows-Vagrant-Box des Vorartikels, lässt sich sofort mit dem Erstellen eines eigenen Basis-Images für Spring-Boot-Anwendungen starten.

Damit sich Java- oder Spring-Boot-Anwendungen innerhalb von Docker-Containern ausführen lassen, ist eine Java-Laufzeitumgebung sowie ein Dockerfile nötig. Hier zeigt sich in der Welt der Docker-Windows-Container ein ähnliches Bild wie in den Vagrant-Boxes des Vorartikels: es gibt schlicht keine passenden Basis-Images für Spring-Boot-Anwendungen. Dazu ist die Technologie wahrscheinlich noch zu jung und man muss selbst aktiv werden.

Mit Ansible stellt das jedoch kein großes Problem dar. Der letzte Schritt in der Datei prepare-docker-windows.yml zeigt den Aufruf im zentralen Playbook:

  - name: Build the springboot-oraclejre-nanoserver Docker image
include: build-springboot-oraclejre-nanoserver-image.yml
vars:
image_name: springboot-oraclejre-nanoserver
java8_update_version: 144
java_build_version: b01
server_jre_name:
server-jre-8u{{java8_update_version}}-windows-x64.tar.gz

Er enthält das Playbook build-springboot-oraclejre-nanoserver-image.yml, das hauptsächlich für zwei Dinge zuständig ist. Zuerst lädt es das Java Runtime Environment (JRE) 8 in der Server-Variante herunter. Damit das automatisch und ohne Benutzerinteraktion klappt, sind ein paar HTTP-Header-Tricks anzuwenden, die sich gut mit dem Tool wget abbilden lassen:

wget.exe --no-cookies --no-check-certificate --header \"Cookie:
oraclelicense=accept-securebackup-cookie\" \"
http://download.oracle.com/otn-pub/java/jdk/8u144-↵
b01/090f390dda5b47b9b721c7dfaa008135/server-jre-8u144-windows-x64.tar.gz\"
-O C:\\springboot-oraclejre-nanoserver\\server-jre-8u131-windows-x64.tar.gz

Im zweiten Schritt baut das System das Basis-Image für Spring-Boot-Anwendungen. Dazu liegt ein Dockerfile in Form eines Templates im gleichnamigen Verzeichnis. Die entsprechende Datei Dockerfile-SpringBoot-OracleJRE-Nanoserver.j2 stellt den Bauplan des Basis-Images dar:

#jinja2: newline_sequence:'\r\n'
FROM microsoft/nanoserver:latest

# This is a base-Image for running Spring Boot Apps on Docker Windows Containers
MAINTAINER Jonas Hecht

# Extract Server-JRE into C:\\jdk1.8.0_xyz in the Container
ADD {{server_jre_name}} /

# Configure Path for easy Java usage
ENV JAVA_HOME=C:\\jdk1.8.0_{{java8_update_version}}
RUN setx /M PATH %PATH%;%JAVA_HOME%\bin

# Create logging default path for Spring Boot
VOLUME C:\\tmp

Als Templating Engine kommt in Ansible Jinja2 zum Einsatz. Die erste Zeile hält das Tool davon ab, alle Zeilen des Dockerfiles in eine einzige zu konvertieren, da am Ende ein Standard-konformes Dockerfile auf der Windows-Vagrant-Box liegen soll. Wie angesprochen nutzt das Basis-Image den Nanoserver als Grundlage. Soll der ungleich größere windowsservercore zum Einsatz kommen, lässt sich die Zeile einfach anpassen.

Interessant ist das darauf folgende Schlüsselwort ADD, da es Docker nicht nur anweist, das vorher mit Ansible heruntergeladene JRE im Docker-Container zu verstauen. Es entpackt es zudem gleich unter C:\jdk1.8.0_{{java8_update_version}}. Für solche Feinheiten der Befehle lohnt es sich, die Dockerfile-Referenzdokumentation genauer zu studieren. Die folgenden Befehle mit den Schlüsselwörtern ENV und RUN setzen für Java notwendige Umgebungsvariablen. Danach wird noch per VOLUME ein Verzeichnis des Windows Docker Host in den Container gemountet. Das ist vor allem für durch Spring Boot bereitgestellte Webanwendungen relevant, bei denen der integrierte Tomcat-Server persistent ins Dateisystem schreiben können muss.

Nun ist alles bereit, um Spring-Boot-Anwendungen in Docker-Windows-Containern laufen lassen zu können. Für eigene Experimente kann jedwede Spring-Boot-Anwendung zum Einsatz kommen. Sie lassen sich zum Beispiel schnell mit dem Spring Initializr erzeugen und durch das Befolgen der Hinweise in den empfehlenswerten "Getting Started Guides" mit Leben füllen. Allerdings ist auch hierfür ein einfaches Beispiel auf GitHub zu finden, das nach einem auf der Kommandozeile ausgeführten mvn clean package eine fertige .jar-Datei ausspuckt und im target-Verzeichnis ablegt.

Darüber hinaus ist dort ein Repository mit Ansible-Skripten zu finden. Nach einem Wechsel in das entsprechende Verzeichnis lässt sich das Playbook direkt ausführen. Sollte eine eigene Spring-Boot-Anwendung zum Einsatz kommen, sind nur die beiden Parameter app_name und jar_input_path entsprechend anzupassen:

ansible-playbook -i hostsfile ansible-windows-docker-springboot.yml ↵
--extra-vars "host=ansible-windows-docker-springboot-dev app_name=restexamples ↵
jar_input_path=../../restexamples/target/restexamples-0.0.1-SNAPSHOT.jar"

Das Playbook ansible-windows-docker-springboot.yml sorgt dabei in vier Abschnitten für alles Notwendige, damit die Spring-Boot-Anwendung sauber innerhalb eines Windows-Containers läuft.

# Prepare for the Docker build...
- name: Create directory C:\spring-boot\app_name, if not there
win_file: path={{target_path}} state=directory

- name: Template and copy Spring Boot app´s Dockerfile to directory ↵
C:\spring-boot\app_name
win_template:
src: "templates/Dockerfile-SpringBoot-App.j2"
dest: "{{target_path}}\\Dockerfile"

- name: Copy Spring Boot app´s jar-File to directory C:\spring-boot\app_name
win_copy:
src: "{{jar_input_path}}"
dest: "{{target_path}}\\{{app_name}}.jar"

Das Skript legt zunächst mit dem Modul win_file das Verzeichnis für den Docker-Build an. Danach kommt das win_template-Modul zum Einsatz, um das Dockerfile-SpringBoot-App.j2 als Standard-konformes Dockerfile im Build-Verzeichnis abzulegen. Es macht von dem in den vorangegangenen Schritten erzeugte Basis-Image Gebrauch und ist durchaus einen Blick wert:

#jinja2: newline_sequence:'\r\n'
FROM springboot-oraclejre-nanoserver:latest

MAINTAINER Jonas Hecht

# Expose the apps Port
EXPOSE {{app_port}}

# Add Spring Boot app.jar to Container
ADD {{app_name}}.jar app.jar

# Fire up our Spring Boot app by default
CMD ["java.exe", "-jar app.jar --server.port={{app_port}}"]

Über das Schlüsselwort FROM lässt sich das Basis-Image als Grundlage definieren. Dadurch steht Java vollständig nutzbar zur Verfügung. An der Stelle ist folglich nur noch an die konkrete Anwendung zu denken. Dazu wird per EXPOSE eine Port als von außen nutzbar deklariert und im Anschluss die Spring-Boot-.jar-Datei mit ADD in den Container unter C:\app.jar kopiert. Die letzte Anweisung im Dockerfile startet die Spring-Boot-Anwendung mit dem gewohnten Befehl java -jar app.jar, wobei das CMD-Schlüsselwort die Syntax vielleicht etwas gewöhnungsbedürftig erscheinen lässt.

Nach dem erfolgreichen Erstellen des Dockerfiles ist zuletzt noch die .jar-Datei der Spring-Boot-Anwendung per win_copy-Modul im selben Verzeichnis abzulegen. Damit ist alles bereit für den Docker-Build-Schritt.