できない.dev

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_oncondition: service_healthy で「健全になるまで待つ」よう指定します。

よくある原因

  1. 短縮記法の限界: depends_on: [db] はコンテナが立ち上がった時点で次へ進み、DB が接続を受け付けるかは見ない。
  2. 初期化の時間差: DB は起動してから接続受付までに数秒かかり、その間にアプリが接続して失敗する。
  3. healthcheck 未定義: 準備完了の判定基準が無いため、待ちようがない。
  4. リトライが無い: アプリが起動時の一度の接続失敗でクラッシュしている。

解決策

1. 依存先に healthcheck を定義する

依存される側(例: PostgreSQL)に、受付可能かを判定するヘルスチェックを定義します。

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

2. depends_on を長い記法にして条件を付ける

depends_on を配列ではなくマップで書き、service_healthy を待ち条件に指定します。
これで db のヘルスチェックが通るまで app は起動しません。

  app:
    build: .
    depends_on:
      db:
        condition: service_healthy

condition には service_started(起動のみ)、service_healthy(健全になるまで)、service_completed_successfully(正常終了まで)が使えます。

3. アプリ側のリトライも併用する

ヘルスチェックを入れても、ネットワークの揺らぎや再起動で一時的に接続が切れることはあります。
最終的な堅牢性のため、アプリ側にも接続リトライ(指数バックオフ)を入れておくと安定します。

この記事は役立ちましたか?