Docker Compose aspetta il contenitore X prima di iniziare Y.

Sto usando rabbitmq e un semplice esempio di pitone da qui insieme a docker-compose. Il mio problema è che ho bisogno di aspettare il completamento di rabbitmq. Da quello che ho cercato fino ad ora, non so come aspettare con container x (nel mio caso worker) finché non viene avviato y (rabbitmq).

Ho trovato questo blogpost dove controlla se l’altro host è online. Ho trovato anche questo comando docker :

aspettare

Utilizzo: docker wait CONTAINER [CONTAINER …]

Blocca fino a quando un container si arresta, quindi stampa il suo codice di uscita.

Aspettare che un container si fermi non è forse quello che sto cercando, ma se lo è, è ansible usare quel comando all’interno di docker-compose.yml? La mia soluzione finora è aspettare qualche secondo e controllare la porta, ma è questo il modo per ottenere questo ?. Se non aspetto, ricevo un errore.

finestra mobile-compose.yml

worker: build: myapp/. volumes: - myapp/.:/usr/src/app:ro links: - rabbitmq rabbitmq: image: rabbitmq:3-management 

campione di 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 per lavoratore:

 FROM python:2-onbuild RUN ["pip", "install", "pika"] CMD ["python","rabbit.py"] 

Aggiornamento novembre 2015 :

Uno script di shell o in attesa all’interno del tuo programma è forse una ansible soluzione. Ma dopo aver visto questo problema, sto cercando un comando o una funzionalità di docker / docker-componga se stesso.

Parlano di una soluzione per l’implementazione di un controllo sanitario, che potrebbe essere l’opzione migliore. Una connessione TCP aperta non significa che il tuo servizio è pronto o potrebbe rimanere pronto. In aggiunta a ciò ho bisogno di cambiare la mia entry point nel mio docker.

Quindi spero di ottenere una risposta con comandi docker-compose a bordo, che si spera che il caso risolva questo problema.

Aggiornamento marzo 2016

C’è una proposta per fornire un modo integrato per determinare se un contenitore è “vivo”. Quindi la docker-compose può forse farne uso nel prossimo futuro.

Aggiornamento giugno 2016

Sembra che lo healthcheck sia integrato nella finestra mobile nella versione 1.12.0

Aggiornamento Januar 2017

Ho trovato una soluzione per la composizione di una finestra mobile: Docker Compose aspetta il contenitore X prima di avviare Y.

Finalmente trovato una soluzione con un metodo docker-compose. Dal momento che il formato di file 2.1 di composizione docker è definito, è ansible definire gli healthcheck .

L’ho fatto in un progetto di esempio che devi installare almeno docker 1.12.0+. Avevo anche bisogno di estendere il file Docker di gestione di rabbitmq , perché l’arricciatura non è installata sull’immagine ufficiale.

Ora provo se la pagina di gestione di rabbitmq-container è disponibile. Se l’arricciatura termina con exitcode 0, l’app contenitore (python pika) verrà avviata e verrà pubblicato un messaggio in coda Hello. Ora funziona (output).

docker-compose (versione 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 

produzione:

 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 

La versione 3 non supporta più il modulo delle condizioni di depends_on . Così mi sono trasferito da depends_on a restart on-failure. Ora il contenitore dell’app si riavvierà 2-3 volte fino a quando non funziona, ma è ancora una funzione di composizione docker senza sovrascrivere il punto di accesso.

docker-compose (versione 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 

Nativamente non è ancora ansible. Vedi anche questa richiesta di funzionalità .

Finora è necessario farlo nei contenitori CMD per attendere fino a quando tutti i servizi richiesti sono lì.

Nel CMD Dockerfile puoi fare riferimento al tuo script di avvio che avvolge l’avvio del tuo servizio contenitore. Prima di avviarlo, aspetti uno a seconda del tipo:

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 

Probabilmente hai bisogno di installare netcat nel tuo Dockerfile . Non so cosa sia preinstallato nell’immagine python.

Ci sono alcuni strumenti là fuori che forniscono logica di attesa facile da usare, per semplici controlli sulle porte TCP:

  • aspettalo
  • dockerize

Per attese più complesse:

  • goss – Blog di spiegazione

Uso del restart: unless-stopped o restart: always può restart: always risolvere questo problema.

Se il container worker si arresta quando rabbitMQ non è pronto, verrà riavviato finché non lo sarà.

Di recente hanno aggiunto la funzione depends_on .

Modificare:

A partire dalla versione depends_on 2.1+ è ansible utilizzare depends_on insieme a healthcheck per ottenere ciò:

Dai documenti :

 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" 

Prima della versione 2.1

È ancora ansible utilizzare depends_on , ma effettua solo l’ ordine in cui i servizi vengono avviati, non se sono pronti prima depends_on del servizio dipendente.

Sembra richiedere almeno la versione 1.6.0.

L’utilizzo sarebbe simile a questo:

 version: '2' services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres 

Dai documenti:

Esprimere la dipendenza tra i servizi, che ha due effetti:

  • docker-compose up avvierà i servizi in ordine di dipendenza. Nell’esempio seguente, db e redis verranno avviati prima del web.
  • la finestra mobile-compose SERVICE includerà automaticamente le dipendenze di SERVICE. Nell’esempio seguente, anche la finestra mobile-compose up creerà e inizierà db e redis.

Nota: a quanto ho capito, anche se questo imposta l’ordine in cui vengono caricati i contenitori. Non garantisce che il servizio all’interno del contenitore sia effettivamente caricato.

Ad esempio, il contenitore Postgres potrebbe essere attivo. Ma il servizio postgres potrebbe ancora inizializzarsi all’interno del contenitore.

puoi anche aggiungerlo all’opzione comando es.

 command: bash -c "sleep 5; start.sh" 

https://github.com/docker/compose/issues/374#issuecomment-156546513

per aspettare su una porta puoi anche usare qualcosa di simile

 command: bash -c "while ! curl -s rabbitmq:5672 > /dev/null; do echo waiting for xxx; sleep 3; done; start.sh" 

per incrementare il tempo di attesa puoi incidere un po ‘di più:

 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" 

Puoi anche risolvere questo problema impostando un endpoint che aspetta che il servizio sia attivo usando netcat (usando lo script docker-wait ). Mi piace questo approccio in quanto hai ancora una sezione di command pulita nella docker-compose.yml e non devi aggiungere codice specifico per la finestra mobile alla tua applicazione:

 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 

Quindi il tuo 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 

Questo è oggigiorno documentato nella documentazione ufficiale della finestra mobile .

PS: è necessario installare netcat nell’istanza della finestra mobile se non è disponibile. Per fare ciò, aggiungi questo al tuo file Docker :

 RUN apt-get update && apt-get install netcat-openbsd -y 

C’è un’utilità pronta all’uso chiamata ” docker-wait ” che può essere utilizzata per l’attesa.

Per l’ordine di ordinazione del contenitore iniziare

 depends_on: 

Per l’attesa del contenitore precedente, iniziare a utilizzare lo script

 entrypoint: ./wait-for-it.sh db:5432 

Questo articolo ti aiuterà https://docs.docker.com/compose/startup-order/

restart: on-failure fatto il trucco per me … vedi sotto

 --- 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" 

basandosi su questo post del blog https://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.html

Ho configurato il mio docker-compose.yml come mostrato di seguito:

 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: {} 

Allora lo faccio per eseguire =>:

docker-compose up start_dependencies

rabbitmq servizio rabbitmq verrà avviato in modalità daemon, start_dependencies completerà il lavoro.