Docker ComposeはコンテナXを待ってからYを開始します


326

私は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()

ワーカーのDockerfile:

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

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

2015年11月の更新

シェルスクリプトまたはプログラム内で待機することは、おそらく可能な解決策です。しかし、この問題が発生した後、私は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がコンテナXを待ってからYを開始します


2
でのヘルスチェックの使用は、Docker-compose 2.3で非推奨になり、分散システムのフォールトトレラント化を促進しています。参照:docs.docker.com/compose/startup-order
Kmaid

回答:


284

最後に、docker-composeメソッドを使用したソリューションを見つけました。ドッキングウィンドウ・コンファイル形式2.1ので、あなたが定義することができるヘルスチェックを

少なくともdocker 1.12.0以降をインストールする必要があるサンプルプロジェクトでそれを行いました。また、curlが公式イメージにインストールされていないため、rabbitmq-management Dockerfile拡張する必要もありました。

次に、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 +カール):

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から失敗時に再起動するようにしました。これで、アプリコンテナーが機能するまで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

6
@svenhornberg pingはICMPを使用しているため、TCPポートをサポートしていません。たぶんncTCPポートをテストすることです。おそらくpsql -h localhost -p 5432何かを使用してクエリする方が良いでしょう。
マット

36
「依存」はバージョン3で削除されましたdocs.docker.com/compose/compose-file/#dependson
nha

48
@nhaのcondition形式depends_onは削除されたようですが、それdepends_on自体はv3でもまだ残っています
akivajgordon 2017

14
が削除された場合depends_on、ヘルスチェックを使用して起動順序を制御できconditionますか?
フランツ

43
このような痛みはまだ信じられません
npr '29

71

本来、それはまだ不可能です。この機能のリクエストもご覧ください。

これまでのところ、必要な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ポートチェックのために、使いやすい待機ロジックを提供するツールがいくつかあります。

より複雑な待機の場合:


CMDの意味を教えてください。これは、ポートチェックで行ったように、私のプログラムがそれを行わなければならないことを意味しますか?または、これはLinuxなどの特定のCMDを意味しますか?
svenhornberg、2015

説明してくれてありがとう、私はあなたの答えに賛成票を投じます。
svenhornberg 2015

44

restart: unless-stoppedまたはを使用してrestart: alwaysこの問題を解決できます。

containerrabbitMQの準備ができていないときにワーカーが停止すると、準備ができるまで再起動されます。


3
私はこの場合のこのソリューションが好きですが、実行するサブプロセスの1つが失敗したときに終了しないコンテナーでは機能しません。たとえば、実行されたJavaサーブレットがデータベースサーバーへの接続に失敗した場合でも、Tomcatコンテナは引き続き実行されます。確かに、Dockerコンテナは、Tomcatのようなサーブレットコンテナをほとんど不要にします。
Derek Mahar、2016年

@ DerekMahar、REST呼び出しのみを提供するJavaベースのWebアプリケーションがある場合、Jetty / Tomcatの代わりに何を使用しますか?
JoeG、16

2
@JoeG、私はTomcatが、組み込みのTomcatではなく、多くのアプリケーションをホストできるサーブレットコンテナを意味していました。Dockerは前者をほとんど不要にしますが、たとえば後者はマイクロサービスでより人気があります。
Derek Mahar、2016

35

ごく最近、depends_on機能が追加されました。

編集:

composeバージョン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"

バージョン2.1より前

は引き続き使用できますがdepends_on、サービスが開始される順序にのみ影響します。依存サービスが開始される前に準備ができている場合は影響を受けません。

少なくともバージョン1.6.0が必要なようです。

使用法は次のようになります。

version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres 

ドキュメントから:

サービス間の依存関係を表します。これには2つの影響があります。

  • docker-compose upは依存関係順にサービスを開始します。次の例では、dbとredisがwebの前に開始されます。
  • docker-compose up SERVICEは、SERVICEの依存関係を自動的に含めます。次の例では、docker-compose up webもdbとredisを作成して起動します。

注:私が理解しているように、これはコンテナーがロードされる順序を設定します。コンテナ内のサービスが実際にロードされたことを保証するものではありません。

たとえば、postgres コンテナが稼働している可能性があります。しかし、postgresサービス自体はまだコンテナー内で初期化されている可能性があります。


10
dnephinは書きました:depends_onは注文だけです。別のコンテナーの開始を実際に遅延させるには、プロセスがそれ自体の初期化を終了したことを検出する何らかの方法が必要になります。
svenhornberg 2016年

15
「バージョン3では、条件フォームのはサポートされなくなりましたdepends_on。」docs.docker.com/compose/compose-file/#dependson
akauppi

depends_onコンテナがready状態になるまで待機しません(あなたのケースで意味することができるものは何でも)。コンテナーが「実行中」の状態になるまで待機します。
htyagi 2017

19

コマンドオプションに追加することもできます。

command: bash -c "sleep 5; start.sh"

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"

待機時間を増やすには、もう少しハッキングできます。

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"

13

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"


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

次にあなたの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

これは現在、公式のDockerドキュメントに記載されています

PS:netcatこれが利用できない場合は、Dockerインスタンスにインストールする必要があります。これを行うには、これをDockerファイルに追加します。

RUN apt-get update && apt-get install netcat-openbsd -y 

4

待機に使用できる「docker-wait」と呼ばれるすぐに使用できるユーティリティがあります。


1
ありがとうございます。これはシェルスクリプトにすぎないため、h3nrikの回答やPython内での待機のようなものです。docker-compose自体の機能ではありません。あなたは、中を見ていてもよいgithub.com/docker/compose/issues/374彼らは最良の方法だろうヘルスを実装する予定です。開いているtcp接続は、サービスの準備ができている、または準備ができていることを意味しません。それに加えて、dockerfileのエントリポイントを変更する必要があります。
svenhornberg 2015

3

多くの異なる方法を試してみましたが、これの単純さを気に入っていました:https : //github.com/ufoscout/docker-compose-wait

:あなたはENVを使用することができるという考えは、このように「待望」しなければならない(ポート付き)サービスホストのリストを提出するドッキングウィンドウのコンポーズファイルでvarsは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

次に、サービスが待機するために、Dockerfileに次の2行を追加する必要があります(他のサービスの開始を待機するサービスのDockerfileに)。

ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait

そのようなサンプルDockerfileの完全な例(再びプロジェクトリポジトリ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

可能な使用法に関するその他の詳細については、READMEを参照してください。


類似の答えを探していました。私は通常、下でnetcatを使用しているため、hub.docker.com / r / dadarek / wait-for-dependenciesを使用してきました。あなたが提供したものはRustベースです。あなたの品質についてコメントすることはできませんが、私にとって追加のレイヤーは間違いなくプロです。
Filip Malczak

1
セキュリティ上の理由から、これはお勧めしません。ハイパーリンクから任意の実行可能ファイルを実行しています。より良い解決策は、COPYを使用して画像にコピーされる静的スクリプトで同じことを行うことです
Paul K

もちろん、@ PaulK、ハイパーリンクから何かを実行することは安全ではないことは理解できますが、それはhttps://github.com/ufoscout/docker-compose-waitライブラリを機能させる方法の上のデモにすぎません:)そのライブラリを使用する方法は、いくつかのlibを利用できるという答えを変更しません。セキュリティは複雑なトピックであり、遠くに行く場合は、たとえそれをコピーしたとしても、とにかくライブラリが何をしているのかを確認する必要があります。ハイパーリンクから」。ヒントに感謝します。
Evereq

2

このブログ投稿に基づくhttps://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.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 =>を実行します。

docker-compose up start_dependencies

rabbitmqサービスはデーモンモードで起動しstart_dependencies、作業を終了します。


lol、プラグイン"curl", "-f", "http://localhost:15672"をインストールする必要があるクエリを作成しmanagement、すでに廃止されたhealthcheckを使用する-その最良の答え。ncそれを介したチェックの簡単な動作例-ダウン投票。ha、ok ...
イゴールコマー

答えはネイティブのDocker機能を使用せず、curl、nc、またはその他のツールを使用する場合は関係ありません。しばらく!ncは、他の回答ですでに投稿されているものと同じです。
svenhornberg


1
@IgorKomar、ありがとう、ありがとう、あなたは私の日を救った!:3実際のアプリケーションが開始される前に、ほぼ同じメカニズムを使用してmysqlサーバーが準備できていることを確認しました。;)私は、次のようなコマンドを渡していますdocker-compose run --name app-test --rm "app" bash -l -c 'echo Waiting for mysql service start... && while ! nc -z db-server 3306; do sleep 1; done && echo Connected! && /bin/bash /script/ci_tests.sh'
TooroSan

1

Docker Composeファイルのバージョン3では、RESTARTを使用できます。

例えば:

docker-compose.yml

worker:
    build: myapp/.
    volumes:
    - myapp/.:/usr/src/app:ro
    restart: on-failure
    depends_on:
    - rabbitmq
rabbitmq:
    image: rabbitmq:3-management

リンクはバージョン3で廃止されたため、リンクの代わりにdepends_onを使用したことに注意してください。

機能しますが、障害が発生するたびにDockerコンテナーを再起動するため、理想的なソリューションではない可能性があります。

RESTART_POLICYご覧ください。再起動ポリシーを微調整できます。

本番環境でCompose使用する場合、実際には再起動ポリシーを使用することがベストプラクティスです。

再起動などの再起動ポリシーの指定:常にダウンタイムを回避する


0

代替ソリューションの1つは、Kubernetesのようなコンテナーオーケストレーションソリューションを使用することです。Kubernetesは、他のコンテナーが開始する前に完了するまで実行されるinitコンテナーをサポートしています。ここでは、SQL Server 2017 Linuxコンテナーの例を見つけることができます。APIコンテナーは、initコンテナーを使用してデータベースを初期化します。

https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html


0

pingの応答を開始するときにmainコンテナーが待機する例を次に示しますworker

version: '3'
services:
  main:
    image: bash
    depends_on:
     - worker
    command: bash -c "sleep 2 && until ping -qc1 worker; do sleep 1; done &>/dev/null"
    networks:
      intra:
        ipv4_address: 172.10.0.254
  worker:
    image: bash
    hostname: test01
    command: bash -c "ip route && sleep 10"
    networks:
      intra:
        ipv4_address: 172.10.0.11
networks:
  intra:
    driver: bridge
    ipam:
      config:
      - subnet: 172.10.0.0/24

ただし、正しい方法はhealthcheck(> = 2.1)を使用することです。


0

深刻な配備にはお勧めしませんが、基本的には「x秒待機」コマンドです。

ではdocker-composeバージョン命令が追加されました。つまり、次のことが可能になります。3.4start_periodhealthcheck

docker-compose.yml

version: "3.4"
services:
  # your server docker container
  zmq_server:
    build:
      context: ./server_router_router
      dockerfile: Dockerfile

  # container that has to wait
  zmq_client:
    build:
      context: ./client_dealer/
      dockerfile: Dockerfile
    depends_on:
      - zmq_server
    healthcheck:
      test: "sh status.sh"
      start_period: 5s

status.sh

#!/bin/sh

exit 0

ここで何が起こるかは、healthcheck5秒後にが呼び出されることです。これによりstatus.shスクリプトが呼び出され、常に「問題なし」が返されます。zmq_clientコンテナーを開始する前に5秒間待機させました!

注:を持っていることが重要ですversion: "3.4"。場合.4がない、ドッキングウィンドウ-COMPOSEは文句を言います。


1
素朴な「5秒待機」ソリューションとして、これはかなり独創的です。私は賛成票を投じますが、本当のような設定では実際には機能せず、誰かが投票数を注意深く読んでしまうのではないかと心配しています。それでも、「男、それは賢い」と言いたかった;)
Filip Malczak '15

PS。より複雑な解決策については、Evereqの回答を参照してください
フィリップマルザック

それがありますないstart_periodありません。この構成は、失敗したヘルスチェックが再試行としてカウントされない猶予期間があることを意味します。それが早く成功した場合、それは健康であると考えられます。開始期間の後、失敗は再試行としてカウントされます。docs.docker.com/engine/reference/builder/#healthcheck
Capi Etherielを

-4

私は2つの作成ファイルを持っているだけで、1つ目を最初に、2つ目を後で開始します。私のスクリプトは次のようになります。

#!/bin/bash
#before i build my docker files
#when done i start my build docker-compose
docker-compose -f docker-compose.build.yaml up
#now i start other docker-compose which needs the image of the first
docker-compose -f docker-compose.prod.yml up

これは良い習慣とは見なされていません。その場合、1つの構成ファイルから複数のconatinerで構成されるソリューションを提供することはできません。
フエルギ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.