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"