network hub compose docker-compose

docker-compose - hub - docker compose version



Docker Compose espera el contenedor X antes de comenzar Y (15)

Aquí está el ejemplo donde el contenedor main espera al worker cuando comienza a responder pings:

#!/bin/sh exit 0

Sin embargo, la forma correcta es usar healthchecks (> = 2.1).

Estoy usando rabbitmq y una simple muestra de python de here junto con docker-compose. Mi problema es que necesito esperar a que rabbitmq se inicie por completo. Por lo que busqué hasta ahora, no sé cómo esperar con el contenedor x (en mi caso trabajador) hasta que se inicie y (rabbitmq).

Encontré esta blogpost donde comprueba si el otro host está en línea. También encontré este comando docker :

Espere

Uso: docker wait CONTENEDOR [CONTENEDOR ...]

Bloquee hasta que un contenedor se detenga, luego imprima su código de salida.

Esperar a que se detenga un contenedor quizás no sea lo que estoy buscando, pero si lo es, ¿es posible usar ese comando dentro de docker-compose.yml? Mi solución hasta ahora es esperar unos segundos y verificar el puerto, pero ¿es esta la forma de lograrlo? Si no espero me sale un error.

docker-compose.yml

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

Python hola muestra (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 para trabajador:

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

Actualización de noviembre de 2015 :

Un script de shell o esperar dentro de su programa es quizás una posible solución. Pero después de ver este Issue , estoy buscando un comando o función de docker / docker-compose.

Mencionan una solución para implementar un control de salud, que puede ser la mejor opción. Una conexión tcp abierta no significa que su servicio esté listo o pueda permanecer listo. Además de eso, necesito cambiar mi punto de entrada en mi dockerfile.

Así que espero una respuesta con los comandos a bordo de Docker-compose, que con suerte será el caso si terminan este problema.

Actualización de marzo de 2016

Existe una proposal para proporcionar una forma integrada de determinar si un contenedor está "vivo". Por lo tanto, Docker-compose puede usarlo en un futuro próximo.

Actualización de junio de 2016

Parece que el control de salud se integrated en Docker en la versión 1.12.0

Actualización enero 2017

Encontré una solución docker-compose ver: Docker Compose espera el contenedor X antes de comenzar Y


En la versión 3 de un archivo Docker Compose, puede usar RESTART .

Por ejemplo:

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

Tenga en cuenta que utilicé depends_on lugar de links ya que este último está en desuso en la versión 3.

Aunque funciona, puede que no sea la solución ideal, ya que reinicia el contenedor acoplable en cada falla.

Eche un vistazo a RESTART_POLICY también. le permite ajustar la política de reinicio.

Cuando usa Compose en producción , en realidad es una buena práctica usar la política de reinicio:

Especificar una política de reinicio como reiniciar: siempre para evitar el tiempo de inactividad


Finalmente encontré una solución con un método docker-compose. Desde el formato de archivo docker-compose 2.1 puede definir healthchecks .

Lo hice en un proyecto de ejemplo que necesita instalar al menos Docker 1.12.0+. También necesitaba extender el Dockerfile rabbitmq-management , porque curl no está instalado en la imagen oficial.

Ahora pruebo si la página de administración del rabbitmq-container está disponible. Si el rizo termina con el código de salida 0, la aplicación de contenedor (python pika) se iniciará y publicará un mensaje en la cola de saludo. Ahora está funcionando (salida).

docker-compose (versión 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

salida:

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 versión 3 ya no admite la forma de condición de depends_on . Así que me mudé de dependen_on para reiniciar en caso de falla. Ahora mi contenedor de aplicaciones se reiniciará 2-3 veces hasta que funcione, pero sigue siendo una función de compilación acoplable sin sobrescribir el punto de entrada.

docker-compose (versión 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


Hay una utilidad lista para usar llamada " docker-wait " que se puede usar para esperar.


Intenté muchas maneras diferentes, pero me gustó la simplicidad de esto: https://github.com/ufoscout/docker-compose-wait

La idea de que puede usar los vars de ENV en el archivo de redacción de docker para enviar una lista de hosts de servicios (con puertos) que se deben "esperar" de esta manera: WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017 .

Entonces, supongamos que tiene el siguiente archivo docker-compose.yml (copy / past de 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

A continuación, para que los servicios esperen, debe agregar las siguientes dos líneas a sus Dockerfiles (en Dockerfile de los servicios que deben esperar a que otros servicios comiencen):

ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait RUN chmod +x /wait

El ejemplo completo de tal Dockerfile de muestra (nuevamente del proyecto 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

Para otros detalles sobre el posible uso, consulte README


Nativamente eso no es posible, todavía. Consulte también esta Issue .

Hasta ahora, debe hacer eso en sus contenedores CMD para esperar hasta que todos los servicios necesarios estén allí.

En el CMD Dockerfile , puede consultar su propio script de inicio que envuelve el inicio de su servicio de contenedor. Antes de comenzar, espera a uno dependiente como:

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

Probablemente también necesite instalar netcat en su Dockerfile . No sé qué está preinstalado en la imagen de Python.

Existen algunas herramientas que proporcionan una lógica de espera fácil de usar, para verificaciones simples de puertos tcp:

Para esperas más complejas:


No se recomienda para implementaciones serias, pero aquí es esencialmente un comando "esperar x segundos".

Con la versión 3.4 docker-compose se ha agregado una instrucción healthcheck a healthcheck . Esto significa que podemos hacer lo siguiente:

docker-compose.yml :

worker: build: myapp/. volumes: - myapp/.:/usr/src/app:ro restart: on-failure depends_on: - rabbitmq rabbitmq: image: rabbitmq:3-management

status.sh :

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

Lo que sucede aquí es que se invoca el healthcheck después de 5 segundos. Esto llama al script status.sh , que siempre devuelve "No hay problema". ¡Acabamos de hacer que el contenedor zmq_client espere 5 segundos antes de comenzar!

Nota: Es importante que tenga la version: "3.4" . Si el .4 no está allí, Docker-compose se queja.


Para el pedido de contenedores comenzar a usar

depends_on:

Para esperar el inicio del contenedor anterior, use el script

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

Este artículo lo ayudará a docs.docker.com/compose/startup-order


Recientemente agregaron la función depends_on .

Editar:

A partir de la versión 2.1+ de compose, puede utilizar depends_on junto con healthcheck para lograr esto:

docs.docker.com/compose/compose-file/#dependson :

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"

Antes de la versión 2.1

Todavía puede usar depends_on , pero solo afecta el orden en que se inician los servicios, no si están listos antes de que se inicie el servicio dependiente.

Parece requerir al menos la versión 1.6.0.

El uso se vería así:

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

De los documentos:

Expresar dependencia entre servicios, que tiene dos efectos:

  • docker-compose up iniciará los servicios en orden de dependencia. En el siguiente ejemplo, db y redis se iniciarán antes que la web.
  • El servicio docker-compose up incluirá automáticamente las dependencias de SERVICE. En el siguiente ejemplo, docker-compose up web también creará e iniciará db y redis.

Nota: Según tengo entendido, aunque esto establece el orden en que se cargan los contenedores. No garantiza que el servicio dentro del contenedor se haya cargado realmente.

Por ejemplo, el contenedor de postgres podría estar activo. Pero el servicio postgres en sí mismo aún podría estar inicializándose dentro del contenedor.


También puede agregarlo a la opción de comando, por ejemplo.

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

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

esperar en un puerto también puedes usar algo como esto

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

para aumentar el tiempo de espera puedes hackear un poco más:

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"


También puede resolver esto estableciendo un punto final que espere a que el servicio esté activo utilizando netcat (utilizando el script docker-wait ). Me gusta este enfoque, ya que todavía tiene una sección de command limpia en su docker-compose.yml y no necesita agregar código específico de docker a su aplicación:

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

Entonces su 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

Esto está documentado hoy en día en la docs.docker.com/compose/startup-order oficial de la docs.docker.com/compose/startup-order .

PD: debe instalar netcat en su instancia de docker si no está disponible. Para hacerlo, agregue esto a su archivo Docker :

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


Una de las soluciones alternativas es utilizar una solución de organización de contenedores como Kubernetes. Kubernetes tiene soporte para contenedores init que se ejecutan hasta su finalización antes de que otros contenedores puedan comenzar. Puede encontrar un ejemplo aquí con el contenedor Linux de SQL Server 2017 donde el contenedor API usa el contenedor init para inicializar una base de datos

https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html


Usar el restart: unless-stopped o restart: always puede resolver este problema.

Si el container trabajo se detiene cuando rabbitMQ no está listo, se reiniciará hasta que lo esté.


basándose en esta publicación de blog https://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.html

Configuré mi docker-compose.yml como se muestra a continuación:

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

Entonces lo hago para ejecutar =>:

docker-compose up start_dependencies

rabbitmq servicio rabbitmq se iniciará en modo demonio, start_dependencies finalizará el trabajo.


restart: on-failure me funcionó ... ver más abajo

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