実践ガイド

Compose で開発環境を立てる

Web + DB の典型構成を Compose で立てる例を通して、depends_on・volumes・.env の使い方をまとめます。

Compose で開発環境を立てる diagram

Compose が解決する問題

docker run を複数回繰り返すと、ネットワーク・ボリューム・環境変数・起動順など、手で管理するものが増えてすぐ破綻します。

Compose は、それらを 1 枚の YAML (compose.yaml) で宣言し、docker compose up 1 発で全部立てる仕組みです。

  • 「アプリ + DB + キャッシュ」のような ローカル開発用のスタック
  • CI でのインテグレーションテスト(DB コンテナを起動して E2E を回す)
  • チーム共通の「動かし方」 をリポジトリで配布できる

これらの用途で定番になっています。

Web + DB の最小構成

Express アプリと PostgreSQL を並べる例です。

# compose.yaml
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:app@db:5432/appdb
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: appdb
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 2s
      timeout: 3s
      retries: 10

volumes:
  db-data:

docker compose up で両方が起動し、Web から db というホスト名で PostgreSQL に接続できます(Compose が自動でサービス名を DNS に登録)。

depends_on の落とし穴

depends_on はよく誤解される機能で、素の depends_on: [db] は「コンテナ起動順」を制御するだけです。

DB プロセスがクエリを受け付けられる状態になったかどうかは見ていません。

解決策は 2 つ。

  1. 依存先に healthcheck を書き、condition: service_healthy で待つ(上記の例)
  2. アプリ側でリトライロジックを実装する(接続失敗時に一定回数再接続)

実運用では両方を組み合わせるのが無難です。

Kubernetes など本番環境では healthcheck が前提になっているので、Compose 開発時点でアプリにリトライを仕込んでおくと移植性が上がります。

volumes: 名前付きと bind mount

Compose で使うボリュームには 2 種類あります。

  • 名前付きボリューム (db-data:/var/lib/postgresql/data): Docker が管理するストレージ。DB など「ホストの中身を直接触りたくないデータ」向け
  • bind mount (./src:/app/src): ホストの特定パスを直接マウント。開発時にソースを編集 → コンテナ内に即反映するのに使う

開発向けには compose.override.yaml に以下のようなオーバーレイを置いて、ソースの bind mount と command: npm run dev のようなウォッチ起動を分離するのが定番です。

# compose.override.yaml
services:
  web:
    volumes:
      - ./:/app
      - /app/node_modules  # ホスト側の node_modules で上書きされないよう無名ボリューム
    command: npm run dev

.env で設定を外出しする

Compose はカレントディレクトリの .env を自動で読み、${VAR} で参照できます。

# .env
POSTGRES_PASSWORD=supersecret
APP_PORT=3000
services:
  web:
    ports:
      - "${APP_PORT}:3000"
  db:
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

運用上のルール:

  • .env.gitignore に入れる
  • コミット用には .env.example を用意し、鍵は空欄にする
  • 本番のシークレットは Compose の secrets: か、クラウドのシークレットマネージャを使う

運用コマンドと片付け

覚えておくと日々が楽になるコマンド一覧です。

# 起動(バックグラウンド)
docker compose up -d

# ログ追尾(サービス指定可)
docker compose logs -f web

# 一時的にサービスを追加で実行(例: マイグレーション)
docker compose run --rm web npm run migrate

# 再ビルドして起動
docker compose up -d --build

# 止めてネットワークも片付け
docker compose down

# データボリュームも削除して完全リセット
docker compose down -v

docker compose down -v はボリュームも消えるので、DB の中身を残したいときは絶対に使わないこと。

開発中にデータを壊してやり直したいときだけ使います。