【Docker】docker-composeでWeb+DB構成を連携させる実践ガイド

Docker

こんにちは、かつコーチです。

前回、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_onhealthcheckの組み合わせです。

depends_on単体は「コンテナの起動順」しか保証しません。

コンテナの中でPostgreSQLのプロセスが実際に接続を受け付けられる状態になったかどうかまでは、depends_onだけでは分からないのです。

これは、レストランで例えると分かりやすくなります。

厨房の照明がついた(コンテナが起動した)だけでは、まだ料理は出せません。

シェフが仕込みを終えて「注文を受け付けられる状態」になって、はじめてホールは配膳を始められます。

healthcheckは、この「仕込み完了」を確認するための仕組みです。

dbサービスにhealthcheckを定義し、web側のdepends_oncondition: 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単体は起動順のみを保証し、サービスの準備完了までは保証しない
  • healthcheckcondition: service_healthyを組み合わせることで、DBの準備完了を待ってから依存サービスを起動できる
  • Dockerネットワーク内ではサービス名がそのままホスト名として解決される
  • 本番運用では機密情報をenvironmentに直書きせず、.envやsecretsで管理する

次に読むべき記事

  • docker-composeとは?複数コンテナをまとめて管理する
  • Dockerネットワークの基本:コンテナ同士をつなぐ
  • ボリュームでデータを永続化する

タグ: Docker, 上級者向け, docker-compose

タイトルとURLをコピーしました