提问者:小点点

Docker Compose在启动Y之前等待容器X


我正在使用rabbitmq和一个简单的python示例以及docker-compose。我的问题是需要等待rabbitmq完全启动。从我到目前为止搜索的内容来看,我不知道如何使用容器x(在我的情况下是worker)等待直到启动y(rabbitmq)。

我发现了这篇博文,他在那里检查另一个主机是否在线。我还找到了这个docker命令:

等等

用法:docker wait CONTAINER[CONTAINER

阻止直到容器停止,然后打印其退出代码。

等待容器停止可能不是我想要的,但如果是的话,是否可以在docker-compose.yml中使用该命令?到目前为止我的解决方案是等待一些秒并检查端口,但这是实现这一点的方法吗?如果我不等,我就会出错。

Docker-compose.yml

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

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

python hello示例(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()

Worker的Dockerfile:

FROM python:2-onbuild
RUN ["pip", "install", "pika"]

CMD ["python","rabbit.py"]

2015年11月更新:

一个shell脚本或在程序内等待也许是一个可能的解决方案。但是在看到这个问题之后,我正在寻找docker/docker-compose本身的一个命令或特性。

他们提到了一个实现健康检查的解决方案,这可能是最好的选择。打开的tcp连接并不意味着您的服务已就绪或可能保持就绪。除此之外,我还需要更改DockerFile中的入口点。

所以我希望得到一个关于docker-compose on board命令的答案,如果他们完成了这个问题,这将是一个很有希望的情况。

2016年3月更新

有一种建议是提供一种内置的方法来确定容器是否是“活动的”。所以docker-compose也许在不久的将来就可以利用它。

2016年6月更新

看来healthcheck将在1.12.0版中集成到docker中

2017年1月更新

我找到了一个docker-compose解决方案(请参阅:Docker Compose wait for container X before


共2个答案

匿名用户

最后用docker-compose方法找到了一个解决方案。由于docker-compose文件格式2.1,您可以定义HealthChecks。

我在一个示例项目中这样做了,您至少需要安装Docker1.12.0+。我还需要扩展rabbitmq-management Dockerfile,因为官方映像上没有安装curl。

现在我测试rabbitmq-container的管理页面是否可用。如果curl以exitcode 0结束,那么容器应用程序(python pika)将被启动并发布一条消息到hello队列。它现在工作(输出)。

docker-compose(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

输出:

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

版本3不再支持depends_on的条件形式。所以我从depends_on转移到restart on-failure。现在我的应用程序容器将重新启动2-3次直到它工作,但它仍然是一个docker-compose特性,没有覆盖入口点。

docker-compose(版本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

匿名用户

从本质上说,这是不可能的。另请参阅此特性请求。

到目前为止,您需要在容器cmd中这样做,以等待所有所需的服务都在那里。

DockerFilecmd中,您可以引用自己的启动脚本,该脚本包装了容器服务的启动。在启动之前,您需要等待一个类似于:

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

您可能还需要在DockerFile中安装netcat。我不知道python映像上预装了什么。

有一些工具提供了简单的tcp端口检查的易于使用的等待逻辑:

  • 等待
  • 对接

对于更复杂的等待:

  • Goss-解释博客