dockerdocker-compose

Docker Compose wait for container X before starting Y


I am using rabbitmq and a simple python sample from here together with docker-compose. My problem is that I need to wait for rabbitmq to be fully started. From what I searched so far, I don't know how to wait with container x (in my case worker) until y (rabbitmq) is started.

I found this blog post where he checks if the other host is online. I also found this docker command:

wait

Usage: docker wait CONTAINER [CONTAINER...]

Block until a container stops, then print its exit code.

Waiting for a container to stop is maybe not what I am looking for but if it is, is it possible to use that command inside the docker-compose.yml? My solution so far is to wait some seconds and check the port, but is this the way to achieve this? If I don't wait, I get an error.

docker-compose.yml

worker:
    build: myapp/.
    volumes:
    - myapp/.:/usr/src/app:ro

    links:
    - rabbitmq
rabbitmq:
    image: rabbitmq:3-management

python hello sample (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"]

Update Nov 2015:

A shell script or waiting inside your program is maybe a possible solution. But after seeing this Issue I am looking for a command or feature of docker/docker-compose itself.

They mention a solution for implementing a health check, which may be the best option. A open tcp connection does not mean your service is ready or may remain ready. In addition to that I need to change my entrypoint in my dockerfile.

So I am hoping for an answer with docker-compose on board commands, which will hopefully the case if they finish this issue.

Update March 2016

There is a proposal for providing a built-in way to determine if a container is "alive". So docker-compose can maybe make use of it in near future.

Update June 2016

It seems that the healthcheck will be integrated into docker in Version 1.12.0

Update January 2017

I found a docker-compose solution see: Docker Compose wait for container X before starting Y


Solution

  • Finally found a solution with a docker-compose method. Since docker-compose file format 2.1 you can define healthchecks.

    I did it in a example project you need to install at least docker 1.12.0+. I also needed to extend the rabbitmq-management Dockerfile, because curl isn't installed on the official image.

    Now I test if the management page of the rabbitmq-container is available. If curl finishes with exitcode 0 the container app (python pika) will be started and publish a message to hello queue. Its now working (output).

    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
    

    output:

    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 no longer supports the condition form of depends_on. So i moved from depends_on to restart on-failure. Now my app container will restart 2-3 times until it is working, but it is still a docker-compose feature without overwriting the entrypoint.

    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