Docker Compose wait for container X before starting Y

+1 vote

I am using rabbitmq and a simple python code together with docker-compose. My problem is that I need to wait for rabbitmq to fully start. I don’t know how to wait with container x ( in my case worker ) until y (rabbitmq) is started.

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

Aug 10, 2018 in Docker by Hannah
• 14,090 points
1,400 views

4 answers to this question.

+2 votes
Best answer

You can use the depends_on feature was has been added recently. According to the docs this can be achieved like this:

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"
answered May 6 by Kunal

selected May 6 by Kalgi
0 votes

Since docker-compose file format 2.1 you can define healthchecks. you need to install at least docker 1.12.0+. you also need to extend the rabbitmq-management Dockerfile, because curl isn't installed on the official image.

Now 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.

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
answered Aug 10, 2018 by Kalgi
• 39,330 points
+1 vote

In the Dockerfiles CMD you could refer to your own start script that wraps starting up your container service. Before you start it, you wait for a depending one like:

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

Probably you need to install netcat in your Dockerfile as well. I do not know what is pre-installed on the python image.

There are a few tools out there that provide easy to use waiting logic, for simple tcp port checks:

  • wait-for-it->is a pure bash script that will wait on the availability of a host and TCP port. It is useful for synchronizing the spin-up of interdependent services, such as linked docker containers. Since it is a pure bash script, it does not have any external dependencies.
  • dockerize -> 

    It is a utility to simplify running applications in docker containers. It allows you to:

  • generate application configuration files at container startup time from templates and container environment variables
  • Tail multiple log files to stdout and/or stderr
  • Wait for other services to be available using TCP, HTTP(S), unix before starting the main process.
answered Aug 10, 2018 by Nilesh
• 6,900 points
+1 vote

You can use something like this:

restart: unless-stopped or restart: always

Have a look at the official docs.

answered May 6 by Nagya

Related Questions In Docker

0 votes
1 answer
0 votes
2 answers
0 votes
1 answer

How to update docker-compose on Docker for Windows?

Please check "version" value in the docker-compose.yml ...READ MORE

answered Sep 20, 2018 in Docker by Tyrion anex
• 8,280 points
68 views
+1 vote
1 answer
0 votes
1 answer
0 votes
1 answer

Deploy Docker Containers from Docker Cloud

To solve this problem, I followed advice ...READ MORE

answered Sep 3, 2018 in AWS by Priyaj
• 56,520 points
136 views