docker compose の depends_on で起動順が待たれない
`depends_on` の短い書き方はコンテナが起動するまでしか待たず、DB などが受付可能になるのは待たない。
`condition: service_healthy` と `healthcheck` を組み合わせて準備完了まで待たせる。
#compose#depends_on#healthcheck#startup
公開: 更新:
要約
depends_on を書いてもアプリが DB より先に動いてしまうのは、短縮記法の depends_on が「依存先コンテナの起動」までしか待たないためです。
公式ドキュメントも「Compose はコンテナが ready になるまでは待たず、起動しているところまでしか待たない」と明記しています。
データベースのように起動後に初期化時間が必要なサービスでは、healthcheck で準備完了を判定し、depends_on の condition: service_healthy で「健全になるまで待つ」よう指定します。
よくある原因
- 短縮記法の限界:
depends_on: [db]はコンテナが立ち上がった時点で次へ進み、DB が接続を受け付けるかは見ない。 - 初期化の時間差: DB は起動してから接続受付までに数秒かかり、その間にアプリが接続して失敗する。
- healthcheck 未定義: 準備完了の判定基準が無いため、待ちようがない。
- リトライが無い: アプリが起動時の一度の接続失敗でクラッシュしている。
解決策
1. 依存先に healthcheck を定義する
依存される側(例: PostgreSQL)に、受付可能かを判定するヘルスチェックを定義します。
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s2. depends_on を長い記法にして条件を付ける
depends_on を配列ではなくマップで書き、service_healthy を待ち条件に指定します。
これで db のヘルスチェックが通るまで app は起動しません。
app:
build: .
depends_on:
db:
condition: service_healthycondition には service_started(起動のみ)、service_healthy(健全になるまで)、service_completed_successfully(正常終了まで)が使えます。
3. アプリ側のリトライも併用する
ヘルスチェックを入れても、ネットワークの揺らぎや再起動で一時的に接続が切れることはあります。
最終的な堅牢性のため、アプリ側にも接続リトライ(指数バックオフ)を入れておくと安定します。