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

sve*_*erg 271 docker-compose

我使用的RabbitMQ并从一个简单的Python样品在这里 一起泊坞窗-撰写.我的问题是我需要等待rabbitmq完全启动.从我到目前为止搜索到的,我不知道如何等待容器x(在我的情况下是工人)直到y(rabbitmq)开始.

我找到了这个博文,他检查其他主机是否在线.我还发现了这个docker命令:

等待

用法:docker等CONTAINER [CONTAINER ...]

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

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

泊坞窗,compose.yml

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

    links:
    - rabbitmq
rabbitmq:
    image: rabbitmq:3-management
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

工作人员的Dockerfile:

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

CMD ["python","rabbit.py"]
Run Code Online (Sandbox Code Playgroud)

2015年11月更新:

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

他们提到了实施健康检查的解决方案,这可能是最佳选择.开放式TCP连接并不意味着您的服务已准备就绪或可能已准备就绪.除此之外,我需要在dockerfile中更改我的入口点.

所以我希望得到一个用docker-compose on board命令的答案,如果他们完成这个问题,希望如此.

2016年3月更新

有一个建议提供一种内置的方法来确定容器是否"活着".所以docker-compose可以在不久的将来使用它.

2016年6月更新

看来健康检查将在版本1.12.0中集成到docker中

2017年1月更新

我发现了一个docker-compose解决方案: Docker Compose在启动Y之前等待容器X.

sve*_*erg 239

终于找到了一个docker-compose方法的解决方案.由于docker-compose文件格式2.1,您可以定义healthchecks.

我在一个示例项目中做到了, 你需要安装至少docker 1.12.0+.我还需要扩展rabbitmq管理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
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

Dockerfile(rabbitmq + curl):

FROM rabbitmq:3-management
RUN apt-get update
RUN apt-get install -y curl 
EXPOSE 4369 5671 5672 25672 15671 15672
Run Code Online (Sandbox Code Playgroud)

版本3不再支持depends_on的条件形式. 所以我从depends_on转移到重启失败.现在我的app容器将重启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
Run Code Online (Sandbox Code Playgroud)

  • @nha看起来`depends_on`的`condition`形式被删除了,但`depends_on`本身仍然在v3中 (40认同)
  • "依赖于"已在版本3中删除https://docs.docker.com/compose/compose-file/#dependson (34认同)
  • 仍然很难相信这样的痛苦 (18认同)
  • 如果`depends_on`与`condition`被删除,健康检查如何仍然用于控制启动顺序? (11认同)
  • 请注意,对 `depends_on.&lt;service&gt;.condition` 的支持实际上已在 v3(当然还有 v2)中卷土重来,因此您可以使用它 — 请参阅[发行说明](https://docs.docker.com /compose/release-notes/#1270),这里是[最新规范](https://github.com/compose-spec/compose-spec/blob/master/spec.md#long-syntax-1)。 (11认同)
  • @svenhornberg`ping`使用ICMP,因此不支持TCP端口.也许`nc`来测试TCP端口.可能更好地使用`psql -h localhost -p 5432`并查询一些东西. (6认同)
  • 我认为主要原因是,如果其他服务不可用,应用程序本身应始终能够等待或恢复(在微服务环境中寻找弹性) (4认同)
  • 不幸的是,在运行测试的情况下,不能选择`restart:on-failure`:C (3认同)
  • 继续使用Compose v2,因为Docker自己将Compose v3称为_sidegrade_到v2.[讨论]中的更多内容(https://github.com/docker/compose/issues/4958#issuecomment-316227127) (3认同)
  • 你好,postgres 也可以这样做吗?我无法让它工作,我正在做这样的测试: `test: ["CMD", "curl", "-f", "http://localhost:5432"]` (2认同)
  • 嗨,curl 不是正确的工具,您需要像 `test: ["CMD", "ping", "-c","1", "localhost:5432"]` 一样 ping 那个端口或调用 http 端点与卷曲。 (2认同)
  • “版本 3 不再支持depends_on 的条件形式。” 官方文档说。有谁知道背后的原因? (2认同)
  • v3 确实支持 `depends_on`,甚至是 `condition` 形式。但是,请参阅https://github.com/docker/docker.github.io/blob/master/compose/compose-file/compose-file-v3.md#depends_on“在集群模式下部署堆栈时,会忽略depends_on选项带有版本 3 Compose 文件。” (2认同)

h3n*_*rik 70

原生那是不可能的.另请参阅此功能请求.

到目前为止,您需要在容器中执行此操作,CMD等待所有必需的服务都存在.

Dockerfiles中,CMD您可以引用自己的启动脚本来启动容器服务.在你开始之前,你要等待一个依赖的人:

Dockerfile

FROM python:2-onbuild
RUN ["pip", "install", "pika"]
ADD start.sh /start.sh
CMD ["/start.sh"]
Run Code Online (Sandbox Code Playgroud)

start.sh

#!/bin/bash
while ! nc -z rabbitmq 5672; do sleep 3; done
python rabbit.py
Run Code Online (Sandbox Code Playgroud)

可能你需要在你的网站上安装netcat Dockerfile.我不知道python镜像上预装了什么.

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

对于更复杂的等待:


Toi*_*lal 41

使用restart: unless-stoppedrestart: always可能解决这个问题.

如果container当RabbitMQ没有准备好时工作器停止,它将重新启动直到它.

  • 我喜欢这种情况下的解决方案,但它不适用于当它运行的子进程之一失败时不退出的容器.例如,即使它运行的Java servlet无法连接到数据库服务器,Tomcat容器也会继续运行.当然,Docker容器渲染像Tomcat这样的servlet容器几乎是不必要的. (3认同)
  • @JoeG,我的意思是Tomcat是可以托管许多应用程序的servlet容器,而不是嵌入式Tomcat.例如,Docker使前者大多不必要,同时使后者更受微服务的欢迎. (2认同)

toa*_*oza 32

最近他们添加了这个depends_on功能.

编辑:

从撰写版本2.1+开始,您可以depends_on结合使用healthcheck来实现此目的:

来自文档:

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"
Run Code Online (Sandbox Code Playgroud)

版本2.1之前

您仍然可以使用depends_on它,但它只影响服务启动的顺序 - 而不是它们在启动相关服务之前就绪.

它似乎至少需要1.6.0版本.

用法看起来像这样:

version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres 
Run Code Online (Sandbox Code Playgroud)

来自文档:

服务之间的快速依赖,有两个影响:

  • docker-compose up将按依赖顺序启动服务.在以下示例中,db和redis将在web之前启动.
  • docker-compose up SERVICE将自动包含SERVICE的依赖项.在以下示例中,docker-compose up web还将创建并启动db和redis.

注意:据我所知,虽然这确实设置了容器的加载顺序.它不保证容器内的服务实际已加载.

例如,postgres 容器可能已启动.但postgres服务本身可能仍在容器内进行初始化.

  • "版本3不再支持`depends_on`的条件形式." https://docs.docker.com/compose/compose-file/#dependson (13认同)
  • [dnephin](https://github.com/dnephin)写道:depends_on只是订购.要实际延迟另一个容器的启动,需要某种方法来检测进程何时完成初始化. (10认同)
  • @akauppi我没有找到任何这样的引用。相反,我看到版本 3 _does_ 支持 `depends_on` (并附有说明,说明如果在集群模式下部署,如何不支持它)请参阅 https://docs.docker.com/compose/compose-file/compose-file-v3/ #depends_on 我已经使用 docker-compose 版本 3.7 在本地进行了测试,它确实支持条件形式的“depends_on”。 (3认同)
  • `depends_on` 不会等到容器处于 `ready` 状态(无论这对你来说意味着什么)。它只等到容器处于“运行”状态。 (2认同)

zoo*_*lin 30

如果您只想启动服务,然后另一个服务成功完成(例如迁移、数据填充等),docker-compose版本 1.29 附带了此功能的内置功能- service_completed_successfully

depends_on:
  <service-name>:
    condition: service_completed_successfully
Run Code Online (Sandbox Code Playgroud)

根据规格

service_completed_successfully- 指定在启动依赖服务之前依赖项预计会成功完成


Ama*_*icA 16

你也可以将它添加到命令选项,例如.

command: bash -c "sleep 5; start.sh"
Run Code Online (Sandbox Code Playgroud)

https://github.com/docker/compose/issues/374#issuecomment-156546513

在端口上等待你也可以使用这样的东西

command: bash -c "while ! curl -s rabbitmq:5672 > /dev/null; do echo waiting for xxx; sleep 3; done; start.sh"
Run Code Online (Sandbox Code Playgroud)

为了增加等待时间你可以更多地破解:

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"
Run Code Online (Sandbox Code Playgroud)


Edw*_*kwu 12

restart: on-failure 为我做了诀窍......见下文

---
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"
Run Code Online (Sandbox Code Playgroud)


qui*_*uit 9

用于容器开始订购使用

depends_on:
Run Code Online (Sandbox Code Playgroud)

等待以前的容器启动使用脚本

entrypoint: ./wait-for-it.sh db:5432
Run Code Online (Sandbox Code Playgroud)

本文将帮助您 https://docs.docker.com/compose/startup-order/

  • @svenhornberg在评论中,你链接,没有关于wait-for-it.sh功能的解释. (4认同)

Eve*_*req 9

尝试了很多不同的方法,但喜欢它的简单性:https : //github.com/ufoscout/docker-compose-wait

您可以使用ENV的想法在泊坞窗撰写文件瓦尔提交服务的主机列表(带口),这应该是“等待”是这样的:WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017

因此,假设您有以下 docker-compose.yml 文件(从 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
Run Code Online (Sandbox Code Playgroud)

接下来,为了让服务等待,您需要将以下两行添加到您的 Dockerfiles(到应该等待其他服务启动的服务的 Dockerfile 中):

ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
Run Code Online (Sandbox Code Playgroud)

此类示例 Dockerfile 的完整示例(再次来自项目 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
Run Code Online (Sandbox Code Playgroud)

有关可能用法的其他详细信息,请参阅自述文件

  • 出于安全考虑,我强烈建议不要这样做。您正在从超链接运行任意可执行文件。更好的解决方案是使用静态脚本执行相同的操作,该脚本通过 COPY 复制到图像中 (2认同)

Mar*_*obs 7

您还可以通过使用netcat(使用docker-wait脚本)设置等待服务启动的端点来解决此问题.我喜欢这种方法,因为你仍然有一个干净的command部分,你docker-compose.yml不需要在你的应用程序中添加特定于docker的代码:

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
Run Code Online (Sandbox Code Playgroud)

然后你的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
Run Code Online (Sandbox Code Playgroud)

现在,这已在官方docker文档中记录.

PS:netcat如果没有,您应该在docker实例中安装.为此,请将此添加到您的Docker文件中:

RUN apt-get update && apt-get install netcat-openbsd -y 
Run Code Online (Sandbox Code Playgroud)


Ewa*_*ren 6

在尝试了几种方法之后,IMO 最简单和最优雅的选择是使用jwilder/dockerize实用程序图像(由 @Henrik Sachse 提到,但他没有显示具体的示例)及其标志-wait。这是一个简单的示例,我需要在启动应用程序之前准备好 RabbitMQ:

version: "3.8"
services:
  # Start RabbitMQ.
  rabbit:
    image: rabbitmq

  # Wait for RabbitMQ to be joinable.
  check-rabbit-started: 
    image: jwilder/dockerize:0.6.1
    depends_on:
      - rabbit
    command: 'dockerize -wait=tcp://rabbit:5672'
  
  # Only start myapp once RabbitMQ is joinable.
  myapp:
    image: myapp:latest
    depends_on:
      - check-rabbit-started
Run Code Online (Sandbox Code Playgroud)


Adr*_*tev 5

有一个名为“ docker-wait ”的即用型实用程序,可用于等待。


Igo*_*mar 5

基于此博客文章https://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependency.html

我的配置docker-compose.yml如下:

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: {}
Run Code Online (Sandbox Code Playgroud)

然后我执行 run =>:

docker-compose up start_dependencies

rabbitmq服务将以守护进程模式启动,start_dependencies完成工作。