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

Seite 2: Container und Images aufräumen

Inhaltsverzeichnis

Bevor mit dem Docker-Build begonnen werden kann, sollte noch etwas aufgeräumt werden:

- name: Stop the Service Docker container
win_shell: docker stop {{app_name}}
ignore_errors: yes

- name: Remove the Service Docker container
win_shell: docker rm {{app_name}} --force
ignore_errors: yes

- name: Remove the Service Docker image
win_shell: docker rmi {{app_name}}:latest --force
ignore_errors: yes

Mithilfe des Moduls win_shell und den Kommandozeilen-Befehlen docker stop appName, docker rm appName und docker rmi imageName werden alte Versionen der Container und Images bereinigt. Da die Schritte nicht beim ersten AusfĂĽhren des Ansible-Playbooks relevant sind, kommt ignore_errors: yes zum Einsatz, das entsprechende Fehler bei der BefehlsausfĂĽhrung einfach ignoriert.

An diesem Beispiel ist vor allem im Vergleich mit der Fülle an Modulen für Docker unter Linux zu erkennen, dass Ansible unter Windows trotz allem noch am Anfang seiner Entwicklung steht. Unter Linux ist es längst nicht mehr nötig, native Shell-Module für Docker zu bemühen. Es ist zu hoffen, dass Red Hat als Treiber hinter Ansible in zukünftigen Versionen noch einige Erweiterungen nachliefert.

Die Spring-Boot-Anwendung ausfĂĽhren

- name: Build the Service´ Docker image
win_shell: docker build . --tag {{app_name}}:latest
args:
chdir: "{{target_path}}"

- name: Run the Service´ Docker container
win_shell: "docker run -d --publish {{app_port}}:{{app_port}} --name= ↵
{{app_name}} --restart=unless-stopped {{app_name}}:latest"

Mit dem Befehl docker build lässt sich der finale Docker-Container für die Spring-Boot-Anwendung bauen. Wichtig ist dabei, dem win_shell-Modul per args: chdir: das korrekte Verzeichnis mitzuteilen, da das Dockerfile sonst nicht gefunden würde und es zu einem Fehler käme. Danach kann der Container gestartet werden. Sinnvoll ist die Verwendung von -d, was den Container "detached" startet und Ansible die Möglichkeit gibt, sich nicht auf ewig an die Ausführung des Containers zu binden.

Durch die Option --publish {{app_port}}:{{app_port}} wird der Port des Docker-Containers direkt auf dem Host zur VerfĂĽgung gestellt. Eine Restart Policy wie unless-stopped sorgt dafĂĽr, dass der Container auch nach einem Neustart des Windows Docker Host beziehungsweise der Windows Vagrant Box wieder zusammen mit dem Docker Windows Service gestartet wird. Die letzte Option veranlasst Docker, das zuvor gebaute Image zu verwenden.

Mit dem Befehl docker logs containerId kann man sich auf einer PowerShell innerhalb der Windows-Vagrant-Box die typischen Logausgaben der Spring-Boot-Anwendung ausgeben lassen:

Die PowerShell offenbart die typischen Logausgaben beim Start einer Spring-Boot-Anwendung.


Bevor die bisherigen Befehle dazu führen, dass Ansible und damit oft die ganze Continuous-Delivery-Pipeline ein vollständiges und erfolgreiches Deployment der Spring-Boot-Anwendung meldet, sollte geprüft werden, ob die Anwendung ordentlich läuft. Der Vorgang ist auch als "Healthcheck" bekannt.

Jede Spring-Boot-Anwendung lässt sich über localhost:port/health fragen, in welchem Zustand sie sich befindet. Im einfachsten Fall kann man davon ausgehen, dass ein erfolgreicher Aufruf der URL auf eine laufende Spring-Boot-Anwendung schließen lässt – zumindest, wenn der Vorgang einen HTTP-Statuscode 200 zurückliefert.

Nun gibt es allerdings noch eine kleine Einschränkung in der aktuellen Docker-Windows-Container-Implementierung: Der sogenannte localhost-Loopback, der normalerweise im Falle von per --publish an den Host gebundenen Ports genau diesen Zugriff auf die Anwendung im Docker-Container zulässt, funktioniert (noch) nicht. Mit ein paar Tricks lassen sich trotzdem Healthchecks durchführen, wie der letzte Abschnitt des Playbooks verdeutlicht:

- name: Obtain the Docker Container´s internal IP address (because localhost ↵
doesn´t work for now https://github.com/docker/for-win/issues/458)
win_shell: "docker inspect -f {% raw %}'{{ ↵
.NetworkSettings.Networks.nat.IPAddress }}' {% endraw %} {{app_name}}↵
{{ '>' }} container_ip.txt"

- name: Get the Docker Container´s internal IP address from the temporary txt-file
win_shell: cat container_ip.txt
register: win_shell_txt_return

- name: Define the IP as variable
set_fact:
docker_container_ip: "{{ win_shell_txt_return.stdout.splitlines()[0] }}"

- name: Wait until our Spring Boot app is up & running
win_uri:
url: "http://{{ docker_container_ip }}:{{port}}/health"
method: GET
register: health_result
until: health_result.status_code == 200
retries: 10
delay: 5
ignore_errors: yes

Mit dem PowerShell-Befehl docker inspect -f {{.NetworkSettings.Networks.nat.IPAddress }} containerName kommt man an die IP des Docker-Containers, auf der sich der Healthcheck erfolgreich ausführen lässt. Leider sieht der Befehl innerhalb von Ansible nicht mehr ganz so elegant aus, da er die im Tool reservierten spitzen Klammern verwendet, die normalerweise auf ein Template hindeuten und vom Programm ersetzt werden wollen. Das ist an der Stelle zu unterbinden, damit der PowerShell-eigene Templating-Mechanismus greifen kann.

Zusätzlich wird eine temporäre Datei für die IP-Adresse benötigt. Das liegt daran, dass die Benutzung einer registrierten Variable Ansible nochmals dazu veranlassen würde, in den abgesetzten Befehl zu schauen, was aktuell leider zu einem Fehler führt und die Ausführung des Skripts abbrechen lässt. Durch den Umweg über die temporäre Testdatei lässt sich das umgehen.

Das Modul set_fact hilft, die ausgelesene Container-IP für die weitere Nutzung in Ansible zu definieren. Danach kann endlich der Healthcheck erfolgen. Hierfür kommt das win_uri-Modul zum Einsatz. Es wird angewiesen, eine HTTP GET-Operation auf die genannte URL auszuführen. Das Programm registriert das Ergebnis als Variable und wartet mit dem Schlüsselwort until auf das Eintreten des korrekten Statuscodes. Mit den darauf folgenden Optionen retries und delay wird der GET-Befehl mehrfach hintereinander in einem bestimmten Zeitintervall ausgeführt. Sobald der letzte Teil des Ansible-Playbooks erfolgreich durchlaufen wurde, lässt sich von einer funktionsfähigen, aktiven Spring-Boot-Anwendung innerhalb eines Docker-Windows-Containers ausgehen.