Docker Composeのdepends_onとHEALTHCHECK|サービス起動順序を確実に制御する設計パターン

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Docker Composeのdepends_onとHEALTHCHECK|サービス起動順序を確実に制御する設計パターン
「docker-compose up を実行したのに、アプリコンテナがDB接続エラーで即座に落ちる」——この問題の原因は、DBコンテナのプロセスが起動しても「接続を受け付ける準備」が整う前にアプリが接続を試みることです。

Docker Compose の depends_oncondition: service_healthy を指定し、Dockerfile の HEALTHCHECK 命令を組み合わせると、DBが完全に起動するまでアプリコンテナの起動を遅らせることができます。

この記事では、depends_on の3種類のconditionとHEALTHCHECKの設定方法を実践例付きで解説します。RHEL 9.4 / Ubuntu 24.04 LTS + Docker 26.x / Compose v2.x で動作確認済みです。

この記事のポイント

・depends_on の condition: service_healthy でDBの準備完了を待ってからアプリを起動できる
・HEALTHCHECK 命令でコンテナの「準備完了」基準を定義する(Dockerfile / Composeファイル)
・docker inspect コマンドでヘルスチェック状態とログを確認してデバッグできる
・起動順序制御だけでなくアプリ側の接続リトライ実装が運用上の鉄則


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

なぜ起動順序の制御が必要なのか

Docker Compose は depends_on を指定しなければ、すべてのコンテナをほぼ同時に起動します。DBが起動完了する前にアプリが接続を試みると、実際には次のようなエラーが発生します。

app_1 | sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) app_1 | could not connect to server: Connection refused app_1 | Is the server running on host "db" (172.18.0.2) and accepting app_1 | TCP/IP connections on port 5432?

depends_on を指定するだけでは「コンテナが起動した(プロセスが開始した)」ことを待つだけです。PostgreSQLがクライアントからの接続を受け付けるまでには、起動プロセスの完了・WAL再生・リスナー開始など数秒のラグがあります。このラグが原因で、本番環境でも同様のトラブルが発生しやすい箇所です。

このラグを確実に吸収するのが ヘルスチェック(HEALTHCHECK)condition: service_healthy の組み合わせです。

depends_onの基本と3種類のcondition

1. service_started(デフォルト・プロセス起動のみ確認)

condition を省略すると service_started が適用されます。コンテナのプロセスが起動した時点で依存関係を満たしたとみなします。DBが接続を受け付ける前に依存コンテナが起動する可能性があるため、DB待ちには使えません。

# condition を省略した例(service_started と同義) services: app: image: myapp:latest depends_on: - db # プロセス起動のみ確認。DB準備完了は保証しない db: image: postgres:16

2. service_healthy(ヘルスチェック通過を待つ)

最も実用的な設定です。依存先コンテナのヘルスチェックが healthy になるまで待機してから、依存元コンテナを起動します。本番・ステージングを問わず、DBが接続を受け付ける状態になってからアプリを起動したい場合はこれを使います。

services: app: image: myapp:latest depends_on: db: condition: service_healthy # dbがhealthyになるまで起動しない db: image: postgres:16 healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5

condition: service_healthy を使うには、依存先コンテナにヘルスチェックが設定されている必要があります。ヘルスチェックがないと service_healthy は永遠に待ち続けます(注意点は後述)。

3. service_completed_successfully(initコンテナの完了を待つ)

DBマイグレーションや初期データ投入など、一度だけ実行して終了するコンテナ(initコンテナ)の完了を待ちたい場合に使います。実際の運用では、本番環境でスキーマ変更を伴うデプロイ時に頻繁に使われます。

services: app: image: myapp:latest depends_on: migrate: condition: service_completed_successfully # マイグレーション完了後に起動 migrate: image: myapp:latest command: python manage.py migrate db: image: postgres:16 healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5

HEALTHCHECK命令でコンテナの「準備完了」を定義する

HEALTHCHECKは「このコンテナが正常に機能している状態とは何か」を定義する仕組みです。設定方法は2種類あります。

1. Dockerfileでの設定

イメージに永続的に焼き込む場合は Dockerfile に記述します。実務では独自イメージを作成する際にこちらを使います。

# PostgreSQLイメージに対するHEALTHCHECKの例 FROM postgres:16 # pg_isready でDBが接続を受け付けているか確認 HEALTHCHECK --interval=5s --timeout=5s --start-period=10s --retries=5 CMD pg_isready -U postgres || exit 1

オプションの意味は次のとおりです。

--interval=5s:チェックを5秒ごとに実行する
--timeout=5s:チェックコマンドが5秒以内に完了しない場合はfailとみなす
--start-period=10s:起動後10秒はfailしてもretryカウントに含めない(起動猶予時間)
--retries=5:5回連続でfailしたらunhealthyとみなす

2. docker-compose.ymlのhealthcheckセクションで設定する

Dockerfile を変更できない(公式イメージをそのまま使う)場合は、Composeファイル内で設定します。こちらのほうが現場での採用頻度は高いです。

services: db: image: postgres:16 environment: POSTGRES_USER: appuser POSTGRES_PASSWORD: secret POSTGRES_DB: appdb healthcheck: test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"] interval: 5s timeout: 5s start_period: 10s retries: 5

test に渡す文字列は CMD-SHELL 形式(シェルで実行)と CMD 形式(exec形式)があります。シェルのパイプや条件式を使う場合は CMD-SHELL を選びます。

実践例:PostgreSQL + Webアプリの起動順序を制御する

1. Composeファイルの全体構成

PostgreSQL と FastAPI(Python)アプリを組み合わせた構成例です。実際の開発・本番環境でそのまま使える構成を示します。

# docker-compose.yml services: db: image: postgres:16 environment: POSTGRES_USER: appuser POSTGRES_PASSWORD: secret POSTGRES_DB: appdb healthcheck: test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"] interval: 5s timeout: 5s start_period: 10s retries: 5 volumes: - pgdata:/var/lib/postgresql/data app: build: . ports: - "8000:8000" environment: DATABASE_URL: "postgresql://appuser:secret@db:5432/appdb" depends_on: db: condition: service_healthy # dbがhealthyになってから起動 restart: on-failure # 接続失敗時にリスタート volumes: pgdata:

restart: on-failure は、ヘルスチェック通過後に万が一DB接続に失敗した場合の保険です。

2. ヘルスチェックの動作確認

docker compose up を実行すると、DBコンテナのヘルスチェックが通過するまで app コンテナの起動が待機されます。

$ docker compose up -d [+] Running 2/2 ✔ Container sample-db-1 Healthy 6.5s ✔ Container sample-app-1 Started 6.8s $ docker compose ps NAME IMAGE STATUS PORTS sample-app-1 myapp:latest Up 10 seconds 0.0.0.0:8000->8000/tcp sample-db-1 postgres:16 Up 15 seconds (healthy) 5432/tcp

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Docker Composeの設計パターンからコンテナ本番運用まで含めた実践的なDocker講座を用意しています。
Dockerマスター講座の詳細はこちら >>

ヘルスチェックが unhealthy になった場合のデバッグ手順

1. docker inspect でステータスとログを確認する

docker inspect を使うと、ヘルスチェックの詳細な実行履歴が取得できます。障害発生時の第一調査コマンドとして覚えておいてください。

# コンテナ名を確認 $ docker compose ps # ヘルスチェック詳細を取得 $ docker inspect sample-db-1 | python3 -m json.tool | grep -A 20 '"Health"' # 出力例(失敗している場合) "Health": { "Status": "unhealthy", "FailingStreak": 3, "Log": [ { "Start": "2026-07-07T08:00:01.234Z", "End": "2026-07-07T08:00:01.239Z", "ExitCode": 1, "Output": "pg_isready: error: connection to server at "localhost" failed" } ] }

Output フィールドにヘルスチェックコマンドの標準エラーが出力されます。このメッセージを起点に原因を特定します。

2. よくある原因と対処

pg_isreadyのユーザー名が違う-U オプションで指定するユーザー名が POSTGRES_USER と一致しているか確認
start_period が短すぎる:大きなDBは初期化に時間がかかるため、start_period: 30s 程度に延ばす
ネットワーク名前解決の失敗:ヘルスチェックはコンテナ自身の内部で実行されるため、localhost または 127.0.0.1 を使う(サービス名は使えない)
testコマンドがコンテナ内に存在しないpg_isready はPostgreSQLクライアントパッケージに含まれる。ベースイメージにない場合は curlwget で代替する

curlを使ったWebサーバーのヘルスチェック例は次のとおりです。

healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 10s timeout: 5s start_period: 15s retries: 3

depends_onとヘルスチェックを使う時の注意点

ヘルスチェックは「起動の遅延」であり「接続の保証」ではありません。(要注意)

ヘルスチェック通過後も一時的にDBへの接続が失敗するケース(高負荷・ネットワーク瞬断)は現場で実際に起こります。アプリ側にも接続リトライ処理を実装するのが運用の鉄則です。

PythonのSQLAlchemyであれば pool_pre_ping=True を設定することで、使用前に接続の生存確認が行われます。

# SQLAlchemy の接続リトライ設定例 from sqlalchemy import create_engine engine = create_engine( "postgresql://appuser:secret@db:5432/appdb", pool_pre_ping=True, # 使用前に接続確認 pool_recycle=3600, # 1時間で接続を再作成 connect_args={"connect_timeout": 10} )

また、Compose v2.20以降では depends_onrequired フィールドで依存サービスが起動できなかった場合の挙動を制御できます(required: false でオプション依存)。本番環境でグレースフルデグレードが必要な場合に活用できます。

本記事のまとめ

Docker Compose の起動順序制御について、depends_on の3種類のconditionとHEALTHCHECKの設定方法を解説しました。

やりたいこと 設定
DBの準備完了を待ってアプリを起動する condition: service_healthy
DBのヘルスチェックを定義する Composefile の healthcheck セクション
initコンテナの完了を待つ condition: service_completed_successfully
ヘルスチェック状態を確認する docker inspect コンテナ名
接続リトライをアプリ側で対処する SQLAlchemy の pool_pre_ping=True
・ヘルスチェックは「DBが接続を受け付けているか」を確認するコマンドを test に指定する
start_period で起動猶予時間を設ける(DBの初期化時間に合わせて調整する)
・ヘルスチェック通過はあくまで「起動の遅延」。アプリ側のリトライ処理も必ず実装する

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Docker Composeの起動順序設計からコンテナ本番運用まで体系的に学べるDocker講座を用意しています。
Dockerマスター講座の詳細はこちら >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。