Wenn Sie einen Dienst in einem Container ausführen, sagen wir mongodb, den Befehl
docker run -d myimage
wird sofort beendet und gibt die Container-ID zurück. In meinem CI-Skript führe ich einen Client aus, um die Mongodb-Verbindung direkt nach dem Ausführen des Mongo-Containers zu testen. Das Problem ist: Der Client kann keine Verbindung herstellen, da der Dienst noch nicht aktiv ist. Abgesehen davon sleep 10
, dass ich in meinem Skript ein großes Element hinzufüge , sehe ich keine Möglichkeit, darauf zu warten, dass ein Container betriebsbereit ist.
Docker hat einen Befehl, wait
der in diesem Fall nicht funktioniert, da der Container nicht vorhanden ist. Ist es eine Einschränkung von Docker?
Fand diese einfache Lösung, suchte nach etwas Besserem, aber kein Glück ...
oder wenn Sie warten möchten, bis der Container als fehlerfrei gemeldet wird (vorausgesetzt, Sie haben einen Healthcheck)
quelle
while [ "`docker inspect -f {{.State.Health.Status}} $container_id`" != "healthy" ]; do sleep 2; done
/usr/bin/docker inspect -f {{.State.Running}} local_mysql
== true $ do sleep 0.1; getan; echo "mysql is on"Wenn Sie die Ports nicht verfügbar machen möchten, wie dies der Fall ist, wenn Sie den Container verknüpfen möchten und möglicherweise mehrere Instanzen zum Testen ausführen, war dies eine gute Möglichkeit, dies in einer Zeile zu tun :) Dieses Beispiel ist basierend auf dem Warten auf die Bereitschaft von ElasticSearch:
Dies setzt voraus, dass wget verfügbar ist, was unter Ubuntu Standard ist. Es wird 5 Mal, 3 Sekunden zwischen den Versuchen, wiederholt, auch wenn die Verbindung abgelehnt wird, und es wird auch nichts heruntergeladen.
quelle
--waitretry=3
anstelle von--wait=3
--wait=seconds Wait the specified number of seconds between the retrievals.
und--waitretry=seconds If you don't want Wget to wait between every retrieval, but only between retries of failed downloads, you can use this option. Wget will use linear backoff, waiting 1 second after the first failure on a given file, then waiting 2 seconds after the second failure on that file, up to the maximum number of seconds you specify.
Wenn der von Ihnen gestartete Containerdienst nicht unbedingt gut auf Curl- oder Wget-Anforderungen reagiert (was für viele Dienste sehr wahrscheinlich ist), können Sie ihn
nc
stattdessen verwenden.Hier ist ein Ausschnitt aus einem Host-Skript, das einen Postgres-Container startet und darauf wartet, dass er verfügbar ist, bevor Sie fortfahren:
Bearbeiten - In diesem Beispiel muss der zu testende Port nicht verfügbar gemacht werden, da auf die vom Docker zugewiesene "private" IP-Adresse für den Container zugegriffen wird. Dies funktioniert jedoch nur, wenn der Docker-Host-Daemon den Loopback (127.xxx) abhört. Wenn Sie (zum Beispiel) auf einem Mac arbeiten und die boot2docker-VM ausführen, können Sie diese Methode nicht verwenden, da Sie von Ihrer Mac-Shell aus nicht zu den "privaten" IP-Adressen der Container weiterleiten können.
quelle
--format
Option seit dieser Antwort geändert hat. Was jetzt funktioniert, istdocker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [NAME|ID...]
(siehe das Beispiel unter docs.docker.com/engine/reference/commandline/inspect ).Angenommen, Sie kennen den Host + -Port Ihres MongoDB-Servers (entweder weil Sie einen verwendet
-link
haben oder weil Sie ihn injiziert haben-e
), können Sie nurcurl
überprüfen, ob der MongoDB-Server ausgeführt wird und Verbindungen akzeptiert.Das folgende Snippet versucht jede Sekunde, eine Verbindung herzustellen, bis es erfolgreich ist:
quelle
IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' mysql)
die IP-Adresse Ihres MySQL-Containers abrufen (wobei "MySQL" der Name oder die Container-ID ist) und die URL durch Folgendes ersetzen :http://$IP:3306
. funktioniert bei mir!Ich habe so etwas wie:
quelle
Ich werfe meine eigene Lösung da draußen:
Ich verwende Docker-Netzwerke, daher hat Marks Netcat-Trick bei mir nicht funktioniert (kein Zugriff vom Host-Netzwerk), und Eriks Idee funktioniert bei einem Postgres-Container nicht (der Container wird als ausgeführt markiert, obwohl Postgres noch nicht vorhanden ist verfügbar, um eine Verbindung herzustellen). Ich versuche also nur, über einen kurzlebigen Container in einer Schleife eine Verbindung zu Postgres herzustellen:
quelle
postgres
Host wird nicht aufgelöst, also benutze ichdocker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' postgres
stattdessen. 2.psql
braucht ein Passwort,pg_isready
passt besser. 3. Mitpg_isready
gibt es auch keine Notwendigkeit in-U myuser
.test/test_runner
$ docker run -v /tmp/mnt:/mnt myimage ruby mnt/test/test_runner
Ich teste so, ob der Port lauscht oder nicht. In diesem Fall habe ich einen Testlauf innerhalb des Containers, aber es ist auch von außen möglich, ob Mongodb bereit ist oder nicht.
$ docker run -p 37017:27017 -d myimage
Überprüfen Sie, ob der Port 37017 vom Host-Container abhört oder nicht.
quelle
Ich musste das frühzeitig angehen und kam auf eine Idee. Als ich für diese Aufgabe recherchierte, kam ich hierher und dachte, ich würde meine Lösung mit zukünftigen Besuchern dieses Beitrags teilen.
Docker-Compose-basierte Lösung
Wenn Sie Docker-Compose verwenden, können Sie meinen Docker-Synchronisations-POC überprüfen . Ich habe einige der Ideen in anderen Fragen kombiniert (danke dafür - positiv bewertet).
Die Grundidee ist, dass jeder Container im Verbund einen Diagnosedienst bereitstellt. Durch Aufrufen dieses Dienstes wird überprüft, ob der erforderliche Satz von Ports im Container geöffnet ist, und der Gesamtstatus des Containers zurückgegeben (WARMUP / RUNNING gemäß POC). Jeder Container verfügt außerdem über ein Dienstprogramm, mit dem beim Start überprüft werden kann, ob die abhängigen Dienste ausgeführt werden. Erst dann startet der Container.
In der Beispiel-Docker-Compose-Umgebung gibt es zwei Dienste, Server1 und Server2, und der Client- Dienst, der auf den Start beider Server wartet und dann eine Anforderung an beide sendet und beendet.
Auszug aus dem POC
wait_for_server.sh
Warten auf mehrere Container:
Grundlegende Implementierung von Diagnostic srervice ( checkports.sh ):
Verdrahtung des Diagnosedienstes mit einem Port:
quelle
Sie können wait-for-it verwenden , ein reines Bash-Skript, das auf die Verfügbarkeit eines Hosts und eines TCP-Ports wartet. Es ist nützlich, um das Hochfahren von voneinander abhängigen Diensten wie verknüpften Docker-Containern zu synchronisieren reines Bash-Skript, es hat keine externen Abhängigkeiten ".
Sie sollten jedoch versuchen, Ihre Dienste so zu gestalten, dass diese Art von Abhängigkeiten zwischen Diensten vermieden werden. Kann Ihr Dienst versuchen, die Verbindung zur Datenbank wiederherzustellen? Können Sie Ihren Container einfach sterben lassen, wenn er keine Verbindung zur Datenbank herstellen kann, und einen Container-Orchestrator (z. B. Docker Swarm) dies für Sie tun lassen?
quelle
Um zu überprüfen, ob ein PostgreSQL- oder MySQL- Docker-Container (derzeit) aktiv ist (speziell für Migrationstools wie Flyway), können Sie die Warte- Binärdatei verwenden: https://github.com/ArcanjoQueiroz/wait-for .
quelle
Docker-Compose-Lösung
Nach dem Docker-Compose kenne ich den Namen des Docker-Containers nicht, also benutze ich
docker inspect -f {{.State.Running}} $(docker-compose ps -q <CONTAINER_NAME>)
und überprüfen Sie
true
wie hier https://stackoverflow.com/a/33520390/7438079quelle
Für die mongoDB Docker-Instanz haben wir dies getan und arbeiten wie ein Zauber:
quelle