J'utilise rabbitmq et un exemple python simple extrait de ici Avec docker-compose. Mon problème est que je dois attendre que rabbitmq soit complètement démarré. D'après ce que j'ai cherché jusqu'à présent, je ne sais pas comment attendre avec le conteneur x (dans mon assistant social) jusqu'à ce que y (rabbitmq) soit démarré.
J'ai trouvé ceci blogpost où il vérifie si l'autre hôte est en ligne . J'ai aussi trouvé ceci commande docker :
attendre
Utilisation: docker wait CONTAINER [CONTAINER ...]
Bloquer jusqu'à ce qu'un conteneur s'arrête, puis imprimer son code de sortie.
Attendre que le conteneur s’arrête n’est peut-être pas ce que je cherche mais si. vérifiez le port, mais est-ce le moyen d'y parvenir? Si je n'attends pas, j'obtiens une erreur.
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
links:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
échantillon python hello (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 for worker:
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
CMD ["python","rabbit.py"]
Mise à jour novembre 2015:
Un script shell ou une attente dans votre programme est peut-être une solution possible. Mais après avoir vu ceci Issue Je cherche une commande ou une fonctionnalité de docker/docker-compose lui-même.
Ils mentionnent une solution pour mettre en œuvre un bilan de santé, qui peut être la meilleure option. Une connexion TCP ouverte ne signifie pas que votre service est prêt ou peut rester prêt. En plus de cela, je dois changer mon point d’entrée dans mon fichier de docker.
J'espère donc une réponse avec les commandes intégrées de docker-compose, ce qui sera le cas si elles résolvent ce problème.
Mise à jour mars 2016
Il existe une proposition pour fournir un moyen intégré de déterminer si un conteneur est "vivant". Donc docker-compose peut peut-être l'utiliser dans un proche avenir.
Mise à jour juin 2016
Il semble que le bilan de santé sera intégré dans docker dans la version 1.12.0.
Mise à jour janvier 2017
J'ai trouvé une solution docker-compose, voir: Docker Compose attend le conteneur X avant de commencer Y
Nativement, ce n'est pas encore possible. Voir aussi cette demande de fonctionnalité .
Jusqu'ici, vous devez le faire dans vos conteneurs CMD
pour attendre que tous les services requis soient disponibles.
Dans Dockerfile
s CMD
, vous pouvez faire référence à votre propre script de démarrage qui encapsule le démarrage de votre service de conteneur. Avant de commencer, vous attendez un type dépendant tel que:
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
Vous devez probablement également installer netcat dans votre Dockerfile
. Je ne sais pas ce qui est pré-installé sur l'image Python.
Il existe quelques outils qui fournissent une logique d’attente facile à utiliser, pour de simples vérifications de ports TCP:
Pour des attentes plus complexes:
Utiliser restart: unless-stopped
ou restart: always
peut résoudre ce problème.
Si l'ouvrier container
s'arrête quand rabbitMQ n'est pas prêt, elle sera redémarrée jusqu'à ce qu'elle le soit.
Tout récemment, ils ont ajouté la fonctionnalité depends_on
.
Modifier:
À compter de la version 2.1+ de Compose, vous pouvez utiliser depends_on
conjointement avec healthcheck
pour atteindre cet objectif:
À partir de la documentation :
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"
Avant la version 2.1
Vous pouvez toujours utiliser depends_on
, mais cela n'affecte que les ordre dans lesquels les services sont démarrés - pas s'ils sont prêts avant le démarrage du service dépendant.
Il semble nécessiter au moins la version 1.6.0.
L'utilisation ressemblerait à quelque chose comme ça:
version: '2'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
De la docs:
Dépendance express entre services, ce qui a deux effets:
- docker-compos up va démarrer les services dans l’ordre des dépendances. Dans l'exemple suivant, db et redis seront démarrés avant Web.
- docker-compos up up SERVICE inclura automatiquement les dépendances de SERVICE. Dans l'exemple suivant, docker-compose up web va également créer et démarrer db et redis.
Note: Si je comprends bien, ceci définit l’ordre dans lequel les conteneurs sont chargés. Cela ne garantit pas que le service à l'intérieur du conteneur a effectivement été chargé.
Par exemple, votre postgres conteneur est peut-être en hausse. Mais le service postgres lui-même pourrait toujours être en cours d'initialisation dans le conteneur.
vous pouvez aussi simplement l'ajouter à l'option de commande, par exemple.
command: bash -c "sleep 5; start.sh"
https://github.com/docker/compose/issues/374#issuecomment-156546513
attendre sur un port, vous pouvez aussi utiliser quelque chose comme ça
command: bash -c "while ! curl -s rabbitmq:5672 > /dev/null; do echo waiting for xxx; sleep 3; done; start.sh"
pour augmenter le temps d'attente, vous pouvez en pirater un peu plus:
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
a fait le tour pour moi ... voir ci-dessous
---
version: '2.1'
services:
consumer:
image: golang:Alpine
volumes:
- ./:/go/src/srv-consumer
working_dir: /go/src/srv-consumer
environment:
AMQP_DSN: "amqp://guest:guest@rabbitmq:5672"
command: go run cmd/main.go
links:
- rabbitmq
restart: on-failure
rabbitmq:
image: rabbitmq:3.7-management-Alpine
ports:
- "15672:15672"
- "5672:5672"
Pour commencer à commander utiliser
depends_on:
Pour attendre le conteneur précédent, commencez par utiliser le script
entrypoint: ./wait-for-it.sh db:5432
Cet article vous aidera https://docs.docker.com/compose/startup-order/
Vous pouvez également résoudre ce problème en définissant un noeud final qui attend que le service soit opérationnel à l'aide de netcat (à l'aide du script docker-wait ). J'aime cette approche car vous avez toujours une section propre command
dans votre docker-compose.yml
et vous n'avez pas besoin d'ajouter de code spécifique à votre menu fixe à votre application:
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
Puis votre docker-entrypoint.sh
:
#!/bin/sh
postgres_Host=$1
postgres_port=$2
shift 2
cmd="$@"
# 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
Ceci est de nos jours documenté dans la documentation officielle docker .
PS: Vous devriez installer netcat
dans votre instance de menu fixe si ce n’est pas disponible. Pour ce faire, ajoutez ceci à votre fichier Docker
:
RUN apt-get update && apt-get install netcat-openbsd -y
Il existe un utilitaire prêt à utiliser appelé " docker-wait " qui peut être utilisé pour attendre.
Dans la version 3 d'un fichier Docker Compose, vous pouvez utiliser RESTART .
Par exemple:
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
restart: on-failure
depends_on:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
Notez que j'ai utilisé depend_on au lieu de liens car ce dernier est déconseillé dans la version 3.
Même si cela fonctionne, il se peut que ce ne soit pas la solution idéale car vous redémarrez le conteneur de menu fixe à chaque échec.
Consultez RESTART_POLICY également. cela vous permet d'affiner la politique de redémarrage.
Lorsque vous tilisez Compose en production , il est préférable d'utiliser la règle de redémarrage:
Spécifier une politique de redémarrage comme redémarrage: toujours pour éviter les temps d'arrêt
en se basant sur ce blog https://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.html
J'ai configuré mon docker-compose.yml
comme indiqué ci-dessous:
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: {}
Alors je fais pour run =>:
docker-compose up start_dependencies
Le service rabbitmq
démarre en mode démon, start_dependencies
termine le travail.
Non recommandé pour les déploiements sérieux, mais il s'agit essentiellement d'une commande "attendre x secondes".
Avec docker-compose
version 3.4
, une instruction start_period
A ÉTÉ AJOUTÉE À healthcheck
. Cela signifie que nous pouvons faire ce qui suit:
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
Qu'est-ce qui se passe ici est que la healthcheck
est invoquée après 5 secondes. Ceci appelle le script status.sh
, qui renvoie toujours "Pas de problème". Nous avons juste fait zmq_client
conteneur attendre 5 secondes avant de commencer!
Remarque: Il est important que vous ayez version: "3.4"
. Si le .4
n'y est pas, docker-compose se plaint.
L'une des solutions alternatives consiste à utiliser une solution d'orchestration de conteneur telle que Kubernetes. Kubernetes prend en charge les conteneurs init qui s’achèvent avant que d’autres conteneurs ne puissent démarrer. Vous pouvez trouver ici un exemple avec le conteneur Linux SQL Server 2017 où le conteneur API utilise le conteneur init pour initialiser une base de données.
https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html
Voici l'exemple où main
conteneur attend worker
lorsqu'il commence à répondre aux pings:
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
Cependant, la méthode appropriée consiste à utiliser healthcheck
(> = 2.1).
Essayé de nombreuses façons différentes, mais a aimé la simplicité de ceci: https://github.com/ufoscout/docker-compose-wait
L'idée que vous pouvez utiliser les vars ENV dans le fichier de composition du menu fixe pour soumettre une liste d'hôtes de services (avec les ports) qui devrait être "attendue" comme ceci: WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
.
Supposons donc que vous ayez le fichier docker-compose.yml suivant (copier/coller du 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
Ensuite, pour que les services attendent, vous devez ajouter les deux lignes suivantes à vos fichiers Docker (dans le fichier Docker des services qui devraient attendre que d’autres services soient lancés):
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
L’exemple complet de cet exemple de fichier Dockerfile (à nouveau tiré du projet repo 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
Pour plus de détails sur les utilisations possibles, voir README