TL;DR
- Docker Compose v2では
depends_onにcondition: service_healthyを明示的に書かないとヘルスチェック完了を待たない - v1の
depends_onは起動順序のみ保証し、v2でもデフォルト動作は同じ - 各サービスに適切な
healthcheckを定義 +depends_onのconditionを設定すれば確実に動作する
環境
- Docker Engine: 27.x
- Docker Compose: v2.29+
- OS: Ubuntu 24.04 LTS / macOS 15
- 再現日: 2026-03-24
問題の症状
docker compose upでWebアプリとDBを起動すると、DBの初期化が完了する前にアプリが接続を試みてエラーになる。
$ docker compose up
[+] Running 3/3
✔ Network app_default Created
✔ Container app-db-1 Started
✔ Container app-web-1 Started
app-web-1 | Error: connect ECONNREFUSED 172.18.0.2:5432
app-web-1 | at TCPConnectWrap.afterConnect [as oncomplete]
app-web-1 exited with code 1
「depends_onでDBを先に起動しているのに、なぜ接続エラーが出るのか?」というのがよくある疑問です。
原因: depends_onはデフォルトで「起動順序」しか保証しない
Docker Composeのdepends_onは、コンテナの起動順序を制御するだけで、サービスが実際にリクエストを受け付ける状態かは確認しません。
PostgreSQLのコンテナがStartedになっても、内部で初期化処理(WALリカバリ、initdb、マイグレーション等)が走っている間はTCP接続を受け付けません。この数秒のギャップでアプリが接続に失敗します。
よくある間違い: healthcheckを書いたのに効かない
以下のような設定では、ヘルスチェックは定義されていますが**depends_on側で参照していない**ため効果がありません。
# NG: healthcheckは定義されているがdepends_onで使っていない
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
web:
image: myapp:latest
depends_on:
- db # ← これは起動順序だけ。healthcheckの完了を待たない
解決方法: condition: service_healthyを追加する
depends_onをオブジェクト形式で書き、condition: service_healthyを指定します。
# OK: healthcheckの完了を待ってからwebを起動する
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
web:
image: myapp:latest
depends_on:
db:
condition: service_healthy # ← これが重要
差分はたった2行です。 depends_onをリスト形式からオブジェクト形式に変え、conditionを追加するだけ。
主要サービスのhealthcheckコマンド一覧
サービスごとに適切なヘルスチェックコマンドが異なります。コピペで使える設定をまとめました。
PostgreSQL
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
MySQL / MariaDB
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD"]
interval: 5s
timeout: 5s
retries: 5
start_period: 15s
CMD-SHELL形式を使うことでシェル経由で実行され、$$MYSQL_ROOT_PASSWORDが環境変数として展開されます($$はCompose内で$をエスケープする書き方)。CMD(exec形式)ではシェル変数展開が行われないため注意してください。
Redis
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
Redisは起動が高速なのでstart_periodは不要なケースが多いです。
MongoDB
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
MongoDB 6.0以降はmongoコマンドが廃止されmongoshになっています。古いイメージではmongo --evalを使ってください。
Elasticsearch
healthcheck:
test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health | grep -qE '\"status\":\"(green|yellow)\"'"]
interval: 10s
timeout: 10s
retries: 10
start_period: 30s
Elasticsearchは初期化に時間がかかるため、start_periodとretriesを多めに設定します。
デバッグ方法
ヘルスチェックが期待通りに動いているか確認する方法です。
1. コンテナのヘルスステータスを確認
$ docker compose ps
NAME IMAGE STATUS PORTS
app-db-1 postgres:16 Up 30s (healthy) 5432/tcp
app-web-1 myapp:latest Up 5s 3000/tcp
STATUS列に(healthy)と表示されていれば正常です。(health: starting)はまだチェック中、(unhealthy)は失敗しています。
2. ヘルスチェックのログを確認
$ docker inspect --format='{{json .State.Health}}' app-db-1 | jq
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2026-03-24T08:00:00.123Z",
"End": "2026-03-24T08:00:00.456Z",
"ExitCode": 0,
"Output": "/var/run/postgresql:5432 - accepting connections\n"
}
]
}
ExitCodeが0なら成功、それ以外ならOutputでエラー内容を確認します。
3. ヘルスチェックを手動実行
# コンテナ内でhealthcheckコマンドを直接実行
$ docker exec app-db-1 pg_isready -U postgres
/var/run/postgresql:5432 - accepting connections
conditionの種類
depends_onのconditionに指定できる値は3つです。
| condition | 動作 | 用途 |
|---|---|---|
service_started |
コンテナが起動したら(デフォルト) | ヘルスチェック不要なサービス |
service_healthy |
ヘルスチェックがhealthyになったら | DB、キャッシュなど |
service_completed_successfully |
コンテナが正常終了(exit 0)したら | マイグレーション、シード処理 |
応用例: マイグレーション実行後にアプリを起動
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
migrate:
image: myapp:latest
command: ["npx", "prisma", "migrate", "deploy"]
depends_on:
db:
condition: service_healthy
web:
image: myapp:latest
depends_on:
migrate:
condition: service_completed_successfully
この構成では、DB起動(healthy) → マイグレーション実行(exit 0) → アプリ起動、の順序が保証されます。
参考リンク
- Docker Compose depends_on 公式ドキュメント
- Docker Compose healthcheck 公式ドキュメント
- PostgreSQL pg_isready リファレンス
- Docker Composeの本番運用設定(ログ集約・リソース制限・secrets管理・マルチステージビルド)については、こちらも参考にしてください: Docker Compose本番環境構築ガイド2026
まとめ
depends_onでヘルスチェック完了を待たせるには、condition: service_healthyの明示的な指定が必須です。healthcheckを定義しただけではdepends_onから参照されず、デフォルトの「起動順序のみ」の動作になります。本記事のサービス別healthcheck設定をコピペして使ってみてください。