Ich benutze rabbitmq und ein einfaches Python-Sample von hier zusammen mit docker-compose. Mein Problem ist, dass ich warten muss, bis rabbitmq vollständig gestartet ist. Nach dem, was ich bisher gesucht habe, weiß ich nicht, wie ich mit Container x (in meinem Fall Worker) warten soll, bis y (rabbitmq) gestartet wird.
Ich habe diesen Blogpost gefunden, in dem er überprüft, ob der andere Host online ist. Ich fand auch diesen Docker-Befehl :
warte
Verwendung: docker wait CONTAINER [CONTAINER ...]
Blockieren Sie, bis ein Container stoppt, und drucken Sie dann den Beendigungscode.
Das Warten auf das Stoppen eines Containers ist möglicherweise nicht das, wonach ich suche. Ist es jedoch möglich, diesen Befehl in der docker-compose.yml zu verwenden? Meine bisherige Lösung besteht darin, einige Sekunden zu warten und den Port zu überprüfen. Ist dies der richtige Weg, um dies zu erreichen? Wenn ich nicht warte, erhalte ich eine Fehlermeldung.
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
links:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
Hallo Python-Beispiel (rabbit.py):
import pika
import time
import socket
pingcounter = 0
isreachable = False
while isreachable is False and pingcounter < 5:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('rabbitmq', 5672))
isreachable = True
except socket.error as e:
time.sleep(2)
pingcounter += 1
s.close()
if isreachable:
connection = pika.BlockingConnection(pika.ConnectionParameters(
Host="rabbitmq"))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print (" [x] Sent 'Hello World!'")
connection.close()
Dockerfile für Arbeiter:
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
CMD ["python","rabbit.py"]
Update November 2015 :
Ein Shell-Skript oder Warten in Ihrem Programm ist möglicherweise eine mögliche Lösung. Aber nachdem ich dieses Problem gesehen habe, suche ich nach einem Befehl oder einer Funktion von docker/docker-compose.
Sie erwähnen eine Lösung für die Durchführung eines Gesundheitschecks, die die beste Option sein kann. Eine offene TCP-Verbindung bedeutet nicht, dass Ihr Dienst bereit ist oder möglicherweise bereit bleibt. Außerdem muss ich meinen Eintrittspunkt in meiner Docker-Datei ändern.
Ich hoffe also auf eine Antwort mit Docker-Compose-On-Board-Befehlen, was hoffentlich der Fall sein wird, wenn sie dieses Problem lösen.
Update März 2016
Es gibt einen Vorschlag für die Bereitstellung einer integrierten Methode, um festzustellen, ob ein Container "lebt". So kann Docker-Compose vielleicht in naher Zukunft davon Gebrauch machen.
Update Juni 2016
Es scheint, dass der Healthcheck in Docker in Version 1.12.0 integriert wird
Update Januar 2017
Ich habe eine Docker-Compose-Lösung gefunden. Siehe: Docker Compose warte auf Container X, bevor Y gestartet wird.
Endlich eine Lösung mit einer Docker-Compose-Methode gefunden. Seit dem Docker-Compose-Dateiformat 2.1 können Sie healthchecks definieren.
Ich habe es in einem Beispielprojekt .__ getan. Sie müssen mindestens Docker 1.12.0 + ..__ installieren. Ich musste auch Erweiterung der rabbitmq-Management Dockerfile , weil curl ist nicht auf dem offiziellen Image installiert.
Jetzt teste ich, ob die Verwaltungsseite des rabbitmq-Containers verfügbar ist. Wenn curl mit Exitcode 0 endet, wird die Container-App (Python Pika) gestartet und eine Nachricht in der Warteschlange „Hallo“ veröffentlicht. Es funktioniert jetzt (Ausgabe).
docker-compose (Version 2.1):
version: '2.1'
services:
app:
build: app/.
depends_on:
rabbit:
condition: service_healthy
links:
- rabbit
rabbit:
build: rabbitmq/.
ports:
- "15672:15672"
- "5672:5672"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
Ausgabe:
rabbit_1 | =INFO REPORT==== 25-Jan-2017::14:44:21 ===
rabbit_1 | closing AMQP connection <0.718.0> (172.18.0.3:36590 -> 172.18.0.2:5672)
app_1 | [x] Sent 'Hello World!'
healthcheckcompose_app_1 exited with code 0
Dockerfile (rabbitmq + curl):
FROM rabbitmq:3-management
RUN apt-get update
RUN apt-get install -y curl
EXPOSE 4369 5671 5672 25672 15671 15672
Version 3 unterstützt nicht mehr die Bedingungsform von abhängig_on . Also wechselte ich von depend_on, um On-Failure neu zu starten. Jetzt wird mein App-Container 2-3 Mal neu gestartet, bis er funktioniert, aber es ist immer noch eine Docker-Compose-Funktion, ohne den Einstiegspunkt zu überschreiben.
docker-compose (Version 3):
version: "3"
services:
rabbitmq: # login guest:guest
image: rabbitmq:management
ports:
- "4369:4369"
- "5671:5671"
- "5672:5672"
- "25672:25672"
- "15671:15671"
- "15672:15672"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
app:
build: ./app/
environment:
- HOSTNAMERABBIT=rabbitmq
restart: on-failure
depends_on:
- rabbitmq
links:
- rabbitmq
Natürlich ist das noch nicht möglich. Siehe auch diese Funktionsanfrage .
Bisher müssen Sie das in Ihren Containern CMD
tun, um zu warten, bis alle erforderlichen Dienste vorhanden sind.
In der Variablen Dockerfile
s CMD
können Sie auf Ihr eigenes Startskript verweisen, das den Start des Container-Services beendet. Bevor Sie damit anfangen, warten Sie auf ein abhängiges wie:
Dockerfile
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
ADD start.sh /start.sh
CMD ["/start.sh"]
start.sh
#!/bin/bash
while ! nc -z rabbitmq 5672; do sleep 3; done
python rabbit.py
Wahrscheinlich müssen Sie netcat auch in Ihrer Dockerfile
installieren. Ich weiß nicht, was auf dem Python-Image vorinstalliert ist.
Es gibt einige Tools, die eine einfache Wartelogik für einfache TCP-Port-Prüfungen bieten:
Für komplexere Wartezeiten:
Die Verwendung von restart: unless-stopped
oder restart: always
kann dieses Problem lösen.
Wenn Worker container
stoppt, wenn rabbitMQ nicht bereit ist, wird es neu gestartet, bis dies der Fall ist.
Vor kurzem haben sie die depends_on
-Funktion hinzugefügt.
Bearbeiten:
Ab Compose Version 2.1+ können Sie depends_on
in Verbindung mit healthcheck
verwenden, um dies zu erreichen:
version: '2.1'
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: redis
healthcheck:
test: "exit 0"
Vor Version 2.1
Sie können zwar weiterhin depends_on
verwenden, dies wirkt sich jedoch nur auf die Reihenfolge aus, in der Dienste gestartet werden, nicht wenn sie bereit sind, bevor der abhängige Dienst gestartet wird.
Es scheint mindestens Version 1.6.0 zu erfordern.
Die Nutzung würde ungefähr so aussehen:
version: '2'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
Aus den Dokumenten:
Expressabhängigkeit zwischen Diensten, die zwei Auswirkungen hat:
- docker-compose up startet Dienste in Abhängigkeitsreihenfolge. Im folgenden Beispiel werden db und redis vor dem Web gestartet.
- docker-compose up SERVICE schließt automatisch die Abhängigkeiten von SERVICE ein. Im folgenden Beispiel erstellt und erstellt docker-compose up web auch db und redis.
Note: Soweit ich es verstehe, legt dies zwar die Reihenfolge fest, in der Container geladen werden. Es kann nicht garantiert werden, dass der Dienst im Container tatsächlich geladen wurde.
Beispielsweise könnten Sie Container postgres up sein. Der Postgres-Dienst selbst wird jedoch möglicherweise noch im Container initialisiert.
sie können es auch einfach zur Befehlsoption hinzufügen, z.
command: bash -c "sleep 5; start.sh"
https://github.com/docker/compose/issues/374#issuecomment-156546513
um auf einen Port zu warten, können Sie auch so etwas verwenden
command: bash -c "while ! curl -s rabbitmq:5672 > /dev/null; do echo waiting for xxx; sleep 3; done; start.sh"
um die Wartezeit zu erhöhen, können Sie ein wenig mehr hacken:
command: bash -c "for i in {1..100} ; do if ! curl -s rabbitmq:5672 > /dev/null ; then echo waiting on rabbitmq for $i seconds; sleep $i; fi; done; start.sh"
restart: on-failure
hat den Trick für mich gemacht
---
version: '2.1'
services:
consumer:
image: golang:Alpine
volumes:
- ./:/go/src/srv-consumer
working_dir: /go/src/srv-consumer
environment:
AMQP_DSN: "amqp://guest:[email protected]:5672"
command: go run cmd/main.go
links:
- rabbitmq
restart: on-failure
rabbitmq:
image: rabbitmq:3.7-management-Alpine
ports:
- "15672:15672"
- "5672:5672"
Verwenden Sie für Container die Bestellung
depends_on:
Zum Warten auf den Start des vorherigen Containers verwenden Sie das Skript
entrypoint: ./wait-for-it.sh db:5432
Dieser Artikel hilft Ihnen dabei https://docs.docker.com/compose/startup-order/
Sie können dieses Problem auch lösen, indem Sie einen Endpunkt festlegen, der mit netcat (mit dem Skript docker-wait ) wartet, bis der Dienst in Betrieb ist. Ich mag diesen Ansatz, da Sie noch einen sauberen command
-Abschnitt in Ihrem docker-compose.yml
haben und Sie Ihrer Anwendung keinen docker-spezifischen Code hinzufügen müssen:
version: '2'
services:
db:
image: postgres
Django:
build: .
command: python manage.py runserver 0.0.0.0:8000
entrypoint: ./docker-entrypoint.sh db 5432
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
Dann dein docker-entrypoint.sh
:
#!/bin/sh
postgres_Host=$1
postgres_port=$2
shift 2
cmd="[email protected]"
# wait for the postgres docker to be running
while ! nc $postgres_Host $postgres_port; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
# run the command
exec $cmd
Dies ist heutzutage in der offiziellen docker-Dokumentation dokumentiert.
PS: Sie sollten netcat
in Ihrer Docker-Instanz installieren, falls diese nicht verfügbar ist. Fügen Sie dies Ihrer Docker
-Datei hinzu:
RUN apt-get update && apt-get install netcat-openbsd -y
Es gibt ein gebrauchsfertiges Dienstprogramm namens " docker-wait ", das zum Warten verwendet werden kann.
In Version 3 einer Docker Compose-Datei können Sie RESTART verwenden.
Zum Beispiel:
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
restart: on-failure
depends_on:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
Beachten Sie, dass ich depend_on anstelle von links verwendet habe, da letzteres in Version 3 veraltet ist.
Auch wenn es funktioniert, ist es möglicherweise nicht die ideale Lösung, da Sie den Docker-Container bei jedem Fehler neu starten.
Schauen Sie sich auch RESTART_POLICY an. Damit können Sie die Neustart-Richtlinie optimieren.
Wenn Sie in der Produktion Compose verwenden , empfiehlt es sich, die Neustartrichtlinie zu verwenden:
Festlegen einer Neustartrichtlinie wie "Neustart": Immer, um Ausfallzeiten zu vermeiden
basierend auf diesem Blogeintrag https://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.html
Ich habe meinen docker-compose.yml
wie folgt konfiguriert:
version: "3.1"
services:
rabbitmq:
image: rabbitmq:3.7.2-management-Alpine
restart: always
environment:
RABBITMQ_HIPE_COMPILE: 1
RABBITMQ_MANAGEMENT: 1
RABBITMQ_VM_MEMORY_HIGH_WATERMARK: 0.2
RABBITMQ_DEFAULT_USER: "rabbitmq"
RABBITMQ_DEFAULT_PASS: "rabbitmq"
ports:
- "15672:15672"
- "5672:5672"
volumes:
- data:/var/lib/rabbitmq:rw
start_dependencies:
image: Alpine:latest
links:
- rabbitmq
command: >
/bin/sh -c "
echo Waiting for rabbitmq service start...;
while ! nc -z rabbitmq 5672;
do
sleep 1;
done;
echo Connected!;
"
volumes:
data: {}
Dann mache ich für run =>:
docker-compose up start_dependencies
Der Dienst rabbitmq
wird im Daemon-Modus gestartet, start_dependencies
beendet die Arbeit.
Nicht empfohlen für ernsthafte Bereitstellungen, aber hier ist im Wesentlichen ein "wait x seconds" -Befehl.
Mit docker-compose
version 3.4
wurde eine start_period
ANWEISUNG ZU healthcheck
hinzugefügt. Dies bedeutet, dass wir Folgendes tun können:
docker-compose.yml
:
version: "3.4"
services:
# your server docker container
zmq_server:
build:
context: ./server_router_router
dockerfile: Dockerfile
# container that has to wait
zmq_client:
build:
context: ./client_dealer/
dockerfile: Dockerfile
depends_on:
- zmq_server
healthcheck:
test: "sh status.sh"
start_period: 5s
status.sh
:
#!/bin/sh
exit 0
Was hier passiert ist, dass die healthcheck
nach 5 Sekunden aufgerufen wird. Dies ruft das status.sh
-Skript auf, das immer "Kein Problem" zurückgibt. Wir haben gerade zmq_client
container 5 Sekunden warten lassen, bevor es losgeht!
Hinweis: Es ist wichtig, dass Sie version: "3.4"
haben. Wenn der .4
nicht vorhanden ist, beschwert sich Docker-Compose.
Eine der alternativen Lösungen ist die Verwendung einer Container-Orchestrierungslösung wie Kubernetes. Kubernetes unterstützt Init-Container, die vollständig ausgeführt werden, bevor andere Container gestartet werden können. Ein Beispiel finden Sie hier mit dem SQL Server 2017-Linux-Container, in dem der API-Container zum Initialisieren einer Datenbank einen Init-Container verwendet
https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html
Hier ist das Beispiel, in dem main
container auf worker
wartet, wenn er auf Pings antwortet:
version: '3'
services:
main:
image: bash
depends_on:
- worker
command: bash -c "sleep 2 && until ping -qc1 worker; do sleep 1; done &>/dev/null"
networks:
intra:
ipv4_address: 172.10.0.254
worker:
image: bash
hostname: test01
command: bash -c "ip route && sleep 10"
networks:
intra:
ipv4_address: 172.10.0.11
networks:
intra:
driver: bridge
ipam:
config:
- subnet: 172.10.0.0/24
Die richtige Methode ist jedoch die Verwendung von healthcheck
(> = 2.1).
Versuchte viele verschiedene Arten, aber mochte die Einfachheit dieses: https://github.com/ufoscout/docker-compose-wait
Die Idee, dass Sie ENV-Variablen in der Docker-Compose-Datei verwenden können, um eine Liste von Service-Hosts (mit Ports) zu senden, die wie folgt "erwartet" werden sollten: WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
.
Nehmen wir also an, Sie haben die folgende docker-compose.yml-Datei (kopieren/einfügen von repo README ):
version: "3"
services:
mongo:
image: mongo:3.4
hostname: mongo
ports:
- "27017:27017"
postgres:
image: "postgres:9.4"
hostname: postgres
ports:
- "5432:5432"
mysql:
image: "mysql:5.7"
hostname: mysql
ports:
- "3306:3306"
mySuperApp:
image: "mySuperApp:latest"
hostname: mySuperApp
environment:
WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
Damit die Dienste warten können, müssen Sie als Nächstes die folgenden zwei Zeilen zu Ihren Dockerdateien hinzufügen (in Dockerdatei der Dienste, die auf den Start anderer Dienste warten sollen):
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
Das vollständige Beispiel für ein solches Dockerfile (ebenfalls aus dem Projektrepo README ):
FROM Alpine
## Add your application to the docker image
ADD MySuperApp.sh /MySuperApp.sh
## Add the wait script to the image
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
## Launch the wait tool and then your application
CMD /wait && /MySuperApp.sh
Für weitere Details zur möglichen Verwendung siehe LIESMICH