こんにちは、かつコーチです。
前回、docker-composeの基本の書き方を解説しました。
今回はその発展編として、Webアプリケーションとデータベースを実際に連携させる構成を組みます。
servicesを並べるだけなら難しくありませんが、実務では「起動順」「接続情報の受け渡し」「起動完了のタイミング」でつまずくケースがほとんどです。
この記事は、docker-composeの基本操作を理解している方を前提に、実践レベルのポイントに絞って解説します。
Web+DB構成のdocker-compose.ymlを設計する
サービス構成の全体像
今回構築するのは、Node.jsアプリケーション(web)とPostgreSQL(db)の2サービス構成です。
services:
web:
build: .
ports:
- "3000:3000"
environment:
DB_HOST: db
DB_PORT: 5432
DB_USER: appuser
DB_PASSWORD: apppass
DB_NAME: appdb
depends_on:
db:
condition: service_healthy
networks:
- app-net
db:
image: postgres:latest
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: apppass
POSTGRES_DB: appdb
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 5s
timeout: 3s
retries: 5
networks:
- app-net
volumes:
db-data:
networks:
app-net:
depends_onとヘルスチェックで起動順を制御する
ここで注目してほしいのが、depends_onとhealthcheckの組み合わせです。
depends_on単体は「コンテナの起動順」しか保証しません。
コンテナの中でPostgreSQLのプロセスが実際に接続を受け付けられる状態になったかどうかまでは、depends_onだけでは分からないのです。
これは、レストランで例えると分かりやすくなります。
厨房の照明がついた(コンテナが起動した)だけでは、まだ料理は出せません。
シェフが仕込みを終えて「注文を受け付けられる状態」になって、はじめてホールは配膳を始められます。
healthcheckは、この「仕込み完了」を確認するための仕組みです。
dbサービスにhealthcheckを定義し、web側のdepends_onでcondition: service_healthyを指定することで、「dbコンテナが起動しただけ」ではなく「dbが実際に接続を受け付けられる状態になってから」webを起動させられます。
サービス間通信の実装
環境変数でDB接続情報を渡す
webサービスのenvironmentで渡しているDB_HOST: dbに注目してください。
Dockerネットワーク内では、サービス名(db)がそのままDNSのホスト名として解決されます。
アプリケーション側のコード(例:Node.jsのpgライブラリ)では、次のようにこの環境変数を読み込むだけで接続できます。
# アプリコンテナ内で環境変数が正しく渡っているか確認する
docker compose exec web env | grep DB_
IPアドレスを直接ハードコードする必要がない点が、Docker Composeネットワークの大きな利点です。
healthcheckがない場合に何が起きるか
healthcheckを設定せず、単純なdepends_on: - dbだけで構成した場合、筆者は実際に以下のエラーに遭遇しました。
Error: connect ECONNREFUSED 172.19.0.2:5432
これは、PostgreSQLコンテナ自体は起動済み(=依存関係上はクリア)だが、DB本体の初期化処理がまだ終わっておらず、接続を受け付けられる状態になっていなかったために発生するエラーです。
特にPostgreSQLは初回起動時にデータディレクトリの初期化処理が入るため、コンテナ起動直後は数秒〜十数秒ほど接続を受け付けません。
この「起動直後だが未完了」の時間差が、healthcheckなしのdepends_onでは検知できない落とし穴です。
実践:起動から動作確認まで
起動と状態確認
構成ファイルができたら、以下のコマンドで起動します。
docker compose up -d
docker compose ps
docker compose psのSTATUS列で、dbサービスがhealthyと表示されていれば、ヘルスチェックが正常に機能している証拠です。
つまずきやすいポイント(Before/After)
❌ Before(healthcheckなし・接続エラーが起きやすい)
web:
depends_on:
- db
✅ After(healthcheck付き・起動完了を待ってから接続)
web:
depends_on:
db:
condition: service_healthy
たった数行の違いですが、この差が「ローカルでは動くのにCI環境では時々失敗する」といった、再現性の低いバグの原因を防ぎます。
応用・一歩先の使い方
機密情報はenvironmentに直書きしない
今回はサンプルとしてenvironmentにパスワードを直書きしましたが、本番運用では.envファイルやsecrets機能を使い、Gitリポジトリに機密情報が含まれないようにするのが定石です。
db:
env_file:
- .env
.envファイルは.gitignoreに追加し、リポジトリには.env.exampleのようなテンプレートだけをコミットする運用が一般的です。
まとめ
この記事のポイント
depends_on単体は起動順のみを保証し、サービスの準備完了までは保証しないhealthcheckとcondition: service_healthyを組み合わせることで、DBの準備完了を待ってから依存サービスを起動できる- Dockerネットワーク内ではサービス名がそのままホスト名として解決される
- 本番運用では機密情報を
environmentに直書きせず、.envやsecretsで管理する
次に読むべき記事
- docker-composeとは?複数コンテナをまとめて管理する
- Dockerネットワークの基本:コンテナ同士をつなぐ
- ボリュームでデータを永続化する
タグ: Docker, 上級者向け, docker-compose