Aloha Leute, wie läuft's?
Letzte Woche war die letzte Oktoberwoche und sollte gruselig sein. Halloween in Zeiten von Covid-19 war lahm. Es gab verständlicherweise keine Party auf die man hätte gehen können, und der zweite Lockdown ist auf dem Weg allen den noch übrigen Spaß zu verderben. Wie auch immer, diese Woche habe ich gelernt, wie man überprüfen kann, ob ein Dienst innerhalb eines Containers gesund ist, und wie ich in einem Bash-Skript darauf reagieren kann. Das möchte ich mit euch teilen. Ihr kennt das Spiel – das ist mehr für mein vergessliches zukünftiges Ich als für alle anderen, aber ihr seid natürlich trotzdem eingeladen, es zu lesen.
Der Fall
Ich musste ein lokales Setup erstellen, um eine bestimmte Java-Bibliothek zu verstehen, die eine AWS SQS mit einer verknüpften DLQ benötigt, um lokal zu laufen. Als Entwickler hast du hier zwei Möglichkeiten: Entweder du nutzt eine richtig konfigurierte AWS SQS mit einer funktionierenden Internetverbindung oder du verwendest einen Localstack Docker-Container. Beide Optionen haben ihre jeweiligen Vor- und Nachteile. Das größte Argument, welches ich für die erste Option gehört habe ist, dass man die meiste Zeit während der Bürozeiten eh in einem Gebäude mit einer funktionierenden Internetverbindung arbeitet und terraform verwenden würde, um die Infrastruktur zu erstellen. Warum also nicht einfach eine Test-Stage für die Integrationstests erstellen? Du hast den Terraform-Code dafür und die neue Test-Stage würde sich genau wie deine Nicht-Live- und Live-Stage verhalten. Ich stimme dieser Aussage zu, und die Schwierigkeit dieser Option hängt von deinem Setup ab. Der Grund, warum ich immer zu Option zwei tendiere ist, dass ich zur Generation "kein Internet verfügbar für dich" gehöre und außerdem oft unterwegs bin, wo man in Deutschland über die Internetverbindung in Zügen nur lachen kann. Diese Docker-Container sind wahre Lebensretter, da man sie lokal ausführen kann und sie nicht viel CPU/RAM deines Laptops benötigen.
Localstack it is!
Das Ding mit Localstack ist, dass jede Funktionalität der AWS Cloud von Localstack simuliert wird. Das Verhalten dieser Dienste ist nicht immer, aber meistens das gleiche wie in der AWS Cloud. Also versuche nicht, komplexe Infrastrukturen in deinem Localstack-Container nachzubauen. Überprüfe den Issue-Tracker auf Fehler, falls etwas nicht wie erwartet funktioniert. Jetzt, da das geklärt ist, lass uns anfangen. Ich werde für dieses Beispiel das Tool aws-cli/2.0.61 und die folgende Docker-Compose-Datei verwenden:
version: '3'
services:
localstack:
image: localstack/localstack:0.10.5
ports:
- "4576:4576"
- "${PORT_WEB_UI-9000}:${PORT_WEB_UI-8080}"
environment:
- SERVICES=sqs
- DEBUG=${DEBUG- }
- DATA_DIR=${DATA_DIR- }
- PORT_WEB_UI=${PORT_WEB_UI- }
- LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
- KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
- DOCKER_HOST=${LOCALSTACK_DOCKER_HOST-unix:///var/run/docker.sock}
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
Zum Zeitpunkt, an dem ich diesen Beitrag schreibe, gibt es bereits eine neuere Version von Localstack (0.11.6), die alle Endpunkte unter einem Dach konsolidiert, aber ich konnte es nicht zum Laufen bringen und habe dazu einen Issue eröffnet. Wie auch immer, du startest den Container mit diesem Shell-Befehl:
docker-compose --file docker-compose-localstack.yaml up --build --detach
Die Optionen bewirken:
- Bauen oder erneutes Bauen deines Dienstes
- Trennen deiner Shell vom Container
Wenn du nicht verstehst, was das bedeutet, versuche den Befehl ohne die zusätzlichen Optionen auszuführen. Du wirst sehen, was passiert oder eher, was nicht passiert.
Da wir nun einen laufenden Docker-Container haben, könnten wir bestimmte Befehle mit awscli verwenden, um beide Queues zu erstellen und sie zu verknüpfen. Aber was wir höchstwahrscheinlich bekommen würden, wenn wir diesen Prozess mit einem Skript automatisieren, ist dieser Fehler:
An error occurred (502) when calling the CreateQueue operation (reached max retries: 2): Bad Gateway
Das passiert, weil wir nicht gewartet haben, bis der Container vollständig gestartet ist. Jetzt könnten wir einfach ein sleep 10 zwischen den Funktionsaufrufen verwenden, aber das ist ungenau und löst das Problem nicht wirklich, stattdessen hilft ein Health-Check.
Bin ich gesund?
Nun möchten wir einen Health-Check zu unserer Docker-Compose-Definition hinzufügen. Wir müssen einen Zustand definieren, wann ein Container als gesund angesehen werden kann. In unserem Fall ist es, wenn der awscli-Befehl list-queues
keinen Fehler zurückgibt. Sieh dir die Dokumentation für mehr Informationen zu Health-Checks an.
version: '3'
services:
localstack:
image: localstack/localstack:0.10.5
ports:
- "4576:4576"
- "${PORT_WEB_UI-9000}:${PORT_WEB_UI-8080}"
environment:
- SERVICES=sqs
- DEBUG=${DEBUG- }
- DATA_DIR=${DATA_DIR- }
- PORT_WEB_UI=${PORT_WEB_UI- }
- LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
- KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
- DOCKER_HOST=${LOCALSTACK_DOCKER_HOST-unix:///var/run/docker.sock}
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
healthcheck:
test: aws --endpoint-url=http://localhost:4576 --region=eu-central-1 --no-sign-request --no-paginate sqs list-queues
interval: 1m30s
timeout: 10s
retries: 3
Lass mich schnell den verwendeten aws-Befehl für den Health-Check aufschlüsseln. Ich definiere den Endpunkt als den lokalen SQS-Endpunkt von Localstack und setze die Region auf eu-central. Jede Region ist hier in Ordnung. Die Option --no-sign-request
sagt aws, die Sicherheitsanmeldeinformationen zu ignorieren, da Localstack diese standardmäßig ignoriert. Die folgende Option --no-paginate
verhindert, dass aws die Ausgabe in einer Subshell kapselt. Es ist in Ordnung, dies nicht zu tun, aber es wird schwerer lesbar.
Der Gesundheitsstatus kann jetzt in der Statusspalte der Ausgabe von docker ps
angezeigt werden.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f341613b827 localstack/localstack:0.10.5 "docker-entrypoint.sh" 23 seconds ago Up 22 seconds (health: starting) 4567-4571/tcp, 0.0.0.0:4572->4572/tcp, 4573-4574/tcp, 0.0.0.0:4575-4576->4575-4576/tcp, 4577-4583/tcp, 0.0.0.0:4584->4584/tcp, 4585-4597/tcp, 0.0.0.0:8080->8080/tcp blogpoststuff_localstack_1
Ein letztes Puzzleteil bleibt: Wie kann ich nun auf den Gesundheitsstatus in einem Bash-Skript reagieren?
Erfinde das Rad nicht neu!
Du kannst auf den Gesundheitsstatus ganz einfach reagieren, indem du dieses Skript von einem Benutzer namens Jordy
verwendest. Das Skript ist ein wahres Schmuckstück und leicht zu verstehen. Der Autor verwendet eine for-Schleife, in der der Status des Health-Checks des Containers überprüft wird. Der Container kann nur drei Zustände haben: starting, unhealthy und healthy.
state=$(docker inspect -f '{{ .State.Health.Status }}' ${container_name})
Jetzt kannst auch du den Gesundheitszustand eines Containers überprüfen.
Cheers