Compose における起動、停止順の制御
サービスの起動順や停止順は、depends_on オプションを使って制御することができます。
Compose では必ず依存順に応じて、コンテナーの起動または停止を行いますが、この依存順とはdepends_on
、links
、volumes_from
、network_mode: "service:..."
によって決定します。
しかし起動時の場合、Compose はコンテナーが「準備状態」になって初めて制御を待ちます。 (これがアプリケーションにとってどのような意味になるかには無関係です。) つまり稼動していることが必要です。 これには十分な理由があります。
たとえばデータベースが準備状態になるまで待ち続けたとすると、分散システムにおいては非常に大きな問題となります。 本番環境であれば利用不能となって、すぐにホストを切り替えなければならなくなります。 アプリケーションは、このような状況に柔軟に対応できるものでなくてはなりません。
こういったことを取り扱う際には、データベースへの接続に失敗した後に、接続を再度確立するようにアプリケーションを設計しておくことが必要です。 アプリケーションが再接続を行えば、そのうちデータベースへの接続が成功します。
最適な方法は、再接続をアプリケーションコード内で行うことです。 これは起動時にも行い、さらに何らかの理由で接続が断たれた際にも行います。 もっともそれほどの柔軟性を必要としないのであれば、以下のようなラッパースクリプトを使ってこの問題を回避する方法もあります。
-
wait-for-it、 dockerize、シェル互換の wait-for、RelayAndContainers テンプレートを利用します。 これは非常に小さなラッパースクリプトです。 これをアプリケーションイメージに含めて、指定されたホストが 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/sh # wait-for-postgres.sh set -e host="$1" shift until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done >&2 echo "Postgres is up - executing command" exec "$@"
このラッパースクリプトを先の例において利用するには、以下のように設定します。
command: ["./wait-for-postgres.sh", "db", "python", "app.py"]