docker-compose の depends_on は「DB 準備完了」を保証しない¶
docker-compose.yml に
depends_on: - postgresと書いた。
アプリが起動してすぐクラッシュする。DB に接続できない。でも postgres は実行中だ。なぜ?
原因: 起動順序 ≠ 準備完了¶
| depends_on が保証すること | 保証しないこと |
|---|---|
| postgres コンテナが「起動(started)」する | postgres が接続を受け付けられる「準備完了(healthy)」状態 |
PostgreSQL の初期化(データディレクトリの作成・ユーザー作成など)には数秒〜十数秒かかるため、コンテナが起動していてもアプリが接続しようとすると失敗する。
解決策 1: healthcheck + condition: service_healthy(推奨)¶
services:
postgres:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 5s
retries: 5
app:
depends_on:
postgres:
condition: service_healthy
解決策 2: アプリ側リトライロジック(推奨)¶
# 指数バックオフでリトライ
def connect_with_retry(dsn, max_retries=10):
for i in range(max_retries):
try:
return psycopg2.connect(dsn)
except psycopg2.OperationalError:
time.sleep(2 ** i)
raise RuntimeError("DB 接続失敗")
解決策 3: wait-for-it.sh などのユーティリティ¶
比較¶
| 方法 | メリット | デメリット |
|---|---|---|
| healthcheck + condition | Docker 標準機能のみ、明確 | healthcheck 設定が必要 |
| アプリ側リトライ | 本番環境でも有効な防御策 | コードが増える |
| wait-for-it.sh | シンプルなシェルスクリプト | 外部依存が増える |
要点¶
-
depends_onはコンテナの「起動順序」だけを制御し、内部の準備完了は保証しない -
本番環境に近い堅牢な設計にするなら healthcheck + アプリ側リトライの両方が望ましい
-
この問題は PostgreSQL 以外(MySQL・Redis・Kafka など)でも同様に発生する