Compose における起動順の制御¶
サービスの起動順は、depends_on オプションを使って制御することができます。
Compose では必ず依存順に応じて、コンテナーの起動を行いますが、この依存順とは depends_on
、 links
、 volumes_from
、 network_mode: "サービス:..."
によって決定します。
しかし起動時の場合、Compose はコンテナーが "準備状態" になって初めて制御を待ちます。 (これがアプリケーションにとってどのような意味になるかには無関係です。) つまり稼動していることが必要です。 これには十分な理由があります。
たとえばデータベースが準備状態になるまで待ち続けたとすると、分散システムにおいては非常に大きな問題となります。 本番環境であれば利用不能となって、すぐにホストを切り替えなければならなくなります。 アプリケーションは、このような状況に柔軟に対応できるものでなくてはなりません。
こういったことを取り扱う際には、データベースへの接続に失敗した後に、接続を再度確立するようにアプリケーションを設計しておくことが必要です。 アプリケーションが再接続を行えば、そのうちデータベースへの接続が成功します。
最適な方法は、再接続をアプリケーションコード内で行うことです。 これは起動時にも行い、さらに何らかの理由で接続が断たれた際にも行います。 もっともそれほどの柔軟性を必要としないのであれば、以下のようなラッパースクリプトを使ってこの問題を回避する方法もあります。
- wait-for-it 、 dockerize 、あるいはシェル互換の wait-for を利用します。 これは非常に小さなラッパースクリプトです。 これをアプリケーションイメージに含めて、指定されたホストが TCP 接続を受け入れるまでの間、指定ポートに問い合わせを行うようにすることができます。
たとえば
wait-for-it.sh
またはwait-for
を使って、サービスコマンドをラップするには以下のようにします。version: "2" services: web: build: . ports: - "80:8000" depends_on: - "db" command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"] db: image: postgresちなみに
この解決方法には限界があります。 たとえば指定するサービスが、本当に準備状態であるかどうかは確認できません。 コマンドにさらに引数を追加して
bash shift
を利用し、ループによって対処するのが次の例です。
- 別の方法として、独自にラッパースクリプトを用意して、アプリケーション特有のヘルスチェックを実現することも考えられます。 たとえば、Postgres が完全に準備状態になって、コマンドを受け付けるようになるまで待ちたいとするなら、以下のスクリプトを用意します。
#!/bin/bash # wait-for-postgres.sh set -e host="$1" shift cmd="$@" until psql -h "$host" -U "postgres" -c '\l'; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done >&2 echo "Postgres is up - executing command" exec $cmdこのラッパースクリプトを先の例において利用するには、以下のように設定します。
command: ["./wait-for-postgres.sh", "db", "python", "app.py"]