gotohayato.com

月(ダークモード)
太陽(ライトモード)

Docker Compose の depends_on の使い方まとめ

Docker

Docker Compose の depends_on の使い方をかんたんにまとめました。

主に自分用のまとめですが、このあたりは公式ドキュメントの説明があまりわかりやすくはないので、 Docker Compose をよく使う方のお役に立つのではないかと思います。

前提

Compose ファイル( docker-compose.yml )のバージョン 3.8 を前提としています。

記事を書く際の動作確認には Docker / Docker Compose の次のバージョンを使用しました:

$ docker --version
Docker version 20.10.5, build 55c4c88
$ docker-compose --version
docker-compose version 1.29.0, build 07737305

depends_on とは

depends_on は Docker Compose の設定ファイルの各サービスにおいて設定できる項目です。 depends_on の名前が示唆するとおりサービス間の依存関係を指定できます。

たとえば次のように書くと service_bservice_a に依存させることができます:

version: "3"
services:
service_a:
image: busybox
service_b:
image: busybox
# `service_b` を `service_a` に依存させる
depends_on:
- service_a

このようにすると docker-compose updocker-compose rundocker-compose stop の実行時に次のような制御が行われます:

  • docker-compose up: service_aservice_b の順に起動する
  • docker-compose run: service_aservice_b の順に起動する
  • docker-compose stop: serivce_bservice_a の順に停止する

depends_on の指定パターン

depends_on は次の 2 つのパターンで指定できます。

  • Short syntax (リスト)
  • Long syntax (オブジェクト)

Short syntax (リスト)

シンプルに単純なリストとして依存関係にあるサービスを記述する方法です。

たとえば次のように設定したサービスは service_a に依存することになります:

depends_on:
- service_a

Long syntax (オブジェクト)

オブジェクト形式で依存関係にあるサービスを記述する方法です。

こちらは依存先に加えて条件の指定が可能です:

depends_on:
service_a:
condition: service_started

条件の指定には condition を使用します。 採りうる選択肢は次の 3 つです:

  1. service_started
  2. service_healthy
  3. service_completed_successfully

condition にデフォルト値は無いので、 long syntax を選ぶ場合は必ず指定する必要があります。

以下長いので先にまとめておくと、それぞれ次のような内容になっています:

選択肢説明
service_started依存先のサービスが起動したら起動する
service_healthy依存先のサービスが起動して、なおかつ、 healthcheck が通ったら起動する
service_completed_successfully依存先のサービスが正常終了したら起動する

以下細かく見ていきます。

1. service_started

service_started は、依存先のサービスが「起動したこと」を条件とします。

condition: service_started

次のように書くと、 service_a の起動後に service_b が起動します:

version: "3"
services:
service_a:
image: busybox
service_b:
image: busybox
depends_on:
service_a:
condition: service_started

実行結果:

$ docker-compose up -d
Creating network "PROJECT_default" with the default driver
Creating PROJECT_service_a_1 ... done
Creating PROJECT_service_b_1 ... done

service_started で注意すべきポイントは、依存先のサービスが起動したら OK であって、そのメインの処理が「待ち受け状態が整ったこと」を確約するものではない点です。 この挙動は、依存元のサービスが正常な動作をするために依存先のサービスの利用が不可欠な場合に問題になることがあります。

たとえば、次のように書くと、この挙動が問題になりうることが確認できます:

version: "3"
services:
# service_a: わざと 5 秒待機した後にウェブサーバーを立ち上げる
service_a:
image: busybox
command:
- sh
- -c
- |
set -ex
sleep 5
echo 'Hi' > /var/www/index.html
httpd -f -p 80 -h /var/www
ports:
- "80:80"
# service_b: service_a に対してリクエストをかける
# 最初の 1 回だけリクエストが失敗してしまう
service_b:
image: busybox
command:
- sh
- -c
- |
while true; do
wget -O- -q http://service_a:80
sleep 5
done
depends_on:
service_a:
condition: service_started

この設定で docker-compose up を実行すると次のようになります:

$ docker-compose up
Creating network "PROJECT_default" with the default driver
Creating PROJECT_service_a_1 ... done
Creating PROJECT_service_b_1 ... done
Attaching to PROJECT_service_a_1, PROJECT_service_b_1
service_b_1 | wget: can't connect to remote host (192.168.240.2): Connection refused
service_a_1 | + sleep 5
service_a_1 | + echo Hi
service_a_1 | + httpd -f -p 80 -h /var/www
service_b_1 | Hi
service_b_1 | Hi

Connection refused ということで、最初の 1 回だけ service_bwget のリクエストが失敗することが確認できます。

なお、 depends_on をリスト形式で指定した場合の挙動は、この service_started を選んだ場合と同じになります。

2. service_healthy

service_healthy は依存先のサービスが起動してなおかつ healthcheck が通ることを条件とするものです。

condition: service_healthy

healthcheck をパスすることが条件なので、 service_healthy を利用する場合は依存先のサービスで healthcheck の設定をしておく必要があります。

参考: healthcheck | Compose file version 3 reference | Docker Documentation

次のように書くと、 service_a の healthcheck が通った後に service_b が起動します:

version: "3"
services:
service_a:
image: busybox
# かんたんに状態を Up に保つためのに httpd を使用する
command: httpd -f
healthcheck:
test: exit 0
# すぐに結果が出るようにタイミングを調整する
interval: 1s
timeout: 1s
retries: 3
start_period: 1s
service_b:
image: busybox
depends_on:
service_a:
condition: service_healthy

実行結果:

$ docker-compose up -d
Creating network "PROJECT_default" with the default driver
Creating PROJECT_service_a_1 ... done
Creating PROJECT_service_b_1 ... done

service_healthy では service_started の場合とは異なり、次のような場合には対象のサービスは起動しません。

  • healthcheck が通らなかった場合
  • 依存先サービスの処理が終了してコンテナが停止した場合

たとえば次のように書くと、 service_a は正常に動いていますが healthcheck が通らないので service_b は起動しません:

version: "3"
services:
service_a:
image: busybox
# かんたんに状態を Up に保つためのに httpd を使用する
command: httpd -f
# healthckeck が通らないようにあえて exit 1 を実行する
healthcheck:
test: exit 1
# すぐに結果が出るようにタイミングを調整する
interval: 1s
timeout: 1s
retries: 3
start_period: 1s
service_b:
image: busybox
depends_on:
service_a:
condition: service_healthy

この設定で docker-compose up -d を実行した後に docker-compose ps を実行すると、 service_a の state 判定が Up (unhealthy) となっていること、そして、 service_b が起動していなかったことが確認できます:

$ docker-compose ps
Name Command State Ports
------------------------------------------------------
PROJECT_service_a_1 httpd -f Up (unhealthy)

また、次のように書いた場合は、 service_a が( sh を実行して)すぐに停止してしまうので、こちらも service_b は起動しません:

version: "3"
services:
service_a:
image: busybox
healthcheck:
test: exit 0
# すぐに結果が出るようにタイミングを調整する
interval: 1s
timeout: 1s
retries: 3
start_period: 1s
service_b:
image: busybox
depends_on:
service_a:
condition: service_healthy

3. service_completed_successfully

service_completed_successfully は依存先のサービスが正常に終了したことを条件とするものです。

condition: service_completed_successfully

service_completed_successfully の場合は依存先のサービスが「終了すること」が必要なので service_startedservice_healthy とは毛色・使いどころがかなり異なります。

次のように書くと、 service_a が起動してすぐに停止した後に service_b が起動します:

version: "3"
services:
# service_a: すぐに正常終了させる
service_a:
image: busybox
command: ["sh", "-c", "exit 0"]
service_b:
image: busybox
depends_on:
service_a:
condition: service_completed_successfully

次のように書くと、 service_a が異常終了するので service_b は起動しません:

version: "3"
services:
# service_a: 異常終了させる
service_a:
image: busybox
command: ["sh", "-c", "exit 1"]
service_b:
image: busybox
depends_on:
service_a:
condition: service_completed_successfully

また、次のように書くと、 service_a が終了しないのでいくら待っても service_b は起動してきません:

version: "3"
services:
# `service_a` を終了させない
service_a:
image: busybox
command: ["sh", "-c", "while true; do echo Hello; sleep 5; done"]
service_b:
image: busybox
depends_on:
service_a:
condition: service_completed_successfully

ちなみに、この service_completed_successfully は 2021 年 2 月に仕様として追加 & 実装された比較的新しい機能です。 docker-compose ではバージョン 1.29.0 ( 2021/04/06 リリース)以降で使えるようになっています。 「 Kubernetes の Init Containers に似た機能を Docker Compose でも使いたい」という考えからリクエストがあり追加されたようです。

参考:

ということで Docker Compose の depends_on のまとめでした。 正確な仕様は compose-spec を参照してください。

参考

compose-specspec.md が最も正確なドキュメントのようです。


後藤隼人 (ごとうはやと)

ウェブ制作・開発やマーケティング、プロジェクト支援などをしています。

GitHubPython

お知らせ

大阪大学医学部附属病院 高度救命救急センターさんが現在クラウドファンディングのプロジェクトをされています(後藤も少しだけ寄附させていただきました)。
© 2021 gotohayato.com
サイトについてタグアーカイブメッセージを送る