0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker Compose v2でdepends_onのhealthcheckが効かない?原因と正しい書き方

0
Last updated at Posted at 2026-03-19

TL;DR

  • Docker Compose v2ではdepends_oncondition: service_healthy明示的に書かないとヘルスチェック完了を待たない
  • v1のdepends_onは起動順序のみ保証し、v2でもデフォルト動作は同じ
  • 各サービスに適切なhealthcheckを定義 + depends_onconditionを設定すれば確実に動作する

環境

  • 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_periodretriesを多めに設定します。

デバッグ方法

ヘルスチェックが期待通りに動いているか確認する方法です。

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"
    }
  ]
}

ExitCode0なら成功、それ以外ならOutputでエラー内容を確認します。

3. ヘルスチェックを手動実行

# コンテナ内でhealthcheckコマンドを直接実行
$ docker exec app-db-1 pg_isready -U postgres
/var/run/postgresql:5432 - accepting connections

conditionの種類

depends_onconditionに指定できる値は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) → アプリ起動、の順序が保証されます。

参考リンク

まとめ

depends_onでヘルスチェック完了を待たせるには、condition: service_healthyの明示的な指定が必須です。healthcheckを定義しただけではdepends_onから参照されず、デフォルトの「起動順序のみ」の動作になります。本記事のサービス別healthcheck設定をコピペして使ってみてください。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?