docker compose の depends_on で起動順が待たれない
depends_on の短い書き方はコンテナが起動するまでしか待たず、DB などが受付可能になるのは待たない。condition: service_healthy と healthcheck を組み合わせて準備完了まで待たせる。
公開: 更新:
要約
depends_on を書いてもアプリが DB より先に動いてしまうのは、短縮記法の depends_on が「依存先コンテナの起動」までしか待たないためです。
公式ドキュメントも「Compose はコンテナが ready になるまでは待たず、起動しているところまでしか待たない」と明記しています。
データベースのように起動後に初期化時間が必要なサービスでは、healthcheck で準備完了を判定し、depends_on の condition: service_healthy で「健全になるまで待つ」よう指定します。
実行例
短い書き方の depends_on では db コンテナが Started になった直後に app が起動し、pg_isready は db:5432 - no response(終了コード 2)を返した。healthcheck と condition: service_healthy を加えた 2 回目は db が Healthy になるのを待ってから app が起動し、accepting connections が返っている。
$ cat compose.yml
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: secret
app:
image: postgres:17-alpine
depends_on:
- db
command: ["sh", "-c", "pg_isready -h db -U postgres; echo \"exit=$?\""]$ docker compose up --abort-on-container-exit app
Network dependsdemo1037_default Creating
Network dependsdemo1037_default Created
Container dependsdemo1037-db-1 Creating
Container dependsdemo1037-db-1 Created
Container dependsdemo1037-app-1 Creating
Container dependsdemo1037-app-1 Created
Attaching to app-1
Container dependsdemo1037-db-1 Starting
Container dependsdemo1037-db-1 Started
Container dependsdemo1037-app-1 Starting
Container dependsdemo1037-app-1 Started
app-1 | db:5432 - no response
app-1 | exit=2
app-1 exited with code 0
Compose Stopping Aborting on container exit...
Container dependsdemo1037-app-1 Stopping
Container dependsdemo1037-app-1 Stopped$ cat compose.yml
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 2s
timeout: 3s
retries: 10
start_period: 5s
app:
image: postgres:17-alpine
depends_on:
db:
condition: service_healthy
command: ["sh", "-c", "pg_isready -h db -U postgres; echo \"exit=$?\""]$ docker compose up --abort-on-container-exit app
Network dependsdemo1037_default Creating
Network dependsdemo1037_default Created
Container dependsdemo1037-db-1 Creating
Container dependsdemo1037-db-1 Created
Container dependsdemo1037-app-1 Creating
Container dependsdemo1037-app-1 Created
Attaching to app-1
Container dependsdemo1037-db-1 Starting
Container dependsdemo1037-db-1 Started
Container dependsdemo1037-db-1 Waiting
Container dependsdemo1037-db-1 Healthy
Container dependsdemo1037-app-1 Starting
Container dependsdemo1037-app-1 Started
app-1 | db:5432 - accepting connections
app-1 | exit=0
app-1 exited with code 0
Compose Stopping Aborting on container exit...
Container dependsdemo1037-app-1 Stopping
Container dependsdemo1037-app-1 Stopped— 2026-09-23 時点の出力
検証環境
- 検証日
- 実行環境
local host (Windows 11 Home, Docker 29.1.3)- バージョン
- Node.js 22.14.0
- npm 10.9.2
- Git 2.48.1.windows.1
- Docker 29.1.3
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- 短縮記法の限界:
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. アプリ側のリトライも併用する
ヘルスチェックを入れても、ネットワークの揺らぎや再起動で一時的に接続が切れることはあります。
最終的な堅牢性のため、アプリ側にも接続リトライ(指数バックオフ)を入れておくと安定します。