Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 625
svenhornberg Avatar asked Jul 31 '15 12:07

svenhornberg


People also ask

How can I wait for a docker container to be up and running?

Start a container in the background. Run docker wait , which should block until the container exits. In another terminal, stop the first container. The docker wait command above returns the exit code.

How do I start docker0?

Starting a docker container The syntax of the docker run command is as follows: $ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...] The command takes the image name, with the optional TAG or DIGEST.

Does Docker compose automatically restart container?

Like the restart Docker command, Docker Compose includes the restart property to restart containers automatically. We can also define restart policies in Docker Compose by providing the restart property to the service in the docker-compose. yml file.

What is the use of docker wait?

The 'docker wait' is a command that is used to wait or block until one or more containers stop, and then it outputs their exit codes which means you cannot use your terminal if you are running the command on the terminal.


2 Answers

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 
like image 83
svenhornberg Avatar answered Sep 21 '22 20:09

svenhornberg


Natively that is not possible, yet. See also this feature request.

So far you need to do that in your containers CMD to wait until all required services are there.

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
  • dockerize

For more complex waits:

  • goss - Explanation blog
like image 28
Henrik Sachse Avatar answered Sep 22 '22 20:09

Henrik Sachse