Docker Compose とは?

Docker Composeは、複数のDockerコンテナをまとめて定義・管理するためのツールです。docker-compose.yml(または compose.yml)というYAMLファイルに設定を書くだけで、Webサーバー・DB・キャッシュなどをワンコマンドで起動できます。

なぜ Docker Compose を使うのか?

課題Docker Compose の解決策
docker run のオプションが長くなるYAMLファイルに設定をまとめる
複数コンテナの起動順序が面倒depends_on で依存関係を定義
開発環境のセットアップが人によって違うcompose.yml で統一
チームメンバーへの共有が大変ファイルをリポジトリにコミットするだけ

インストール

Docker Desktop をインストールすると Docker Compose も含まれています。

# バージョン確認
docker compose version
# Docker Compose version v2.24.0

# 旧コマンド(ハイフンあり)も動くがv2推奨
docker-compose version

v1 と v2 の違い

# v1(非推奨)
docker-compose up

# v2(推奨)
docker compose up

v2 は Docker CLI のプラグインとして動作し、パフォーマンスが向上しています。

基本的な compose.yml の書き方

最小構成

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
# 起動
docker compose up

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

# 停止
docker compose down

よくある開発環境構成

services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  db-data:

主要なキーワード解説

services

コンテナの定義を記述するトップレベルのキーです。

services:
  サービス名:
    # コンテナの設定

image vs build

services:
  # 既存のイメージを使う場合
  nginx:
    image: nginx:latest

  # Dockerfile からビルドする場合
  app:
    build: .

  # ビルドオプションを細かく指定する場合
  app-custom:
    build:
      context: .
      dockerfile: Dockerfile.dev
      args:
        NODE_VERSION: 20

ports

services:
  app:
    ports:
      # ホスト:コンテナ
      - "3000:3000"
      # ホストのポートをランダムに割り当て
      - "3000"
      # 特定のIPにバインド
      - "127.0.0.1:3000:3000"

volumes

services:
  app:
    volumes:
      # バインドマウント(ホストのディレクトリをマウント)
      - ./src:/app/src
      # 名前付きボリューム
      - node-modules:/app/node_modules
      # 読み取り専用
      - ./config:/app/config:ro

volumes:
  node-modules:

environment と env_file

services:
  app:
    # 直接指定
    environment:
      - NODE_ENV=development
      - API_KEY=my-secret-key

    # ファイルから読み込み
    env_file:
      - .env
      - .env.local

depends_on

services:
  app:
    depends_on:
      # 単純な起動順序
      - db
      - redis

  app-v2:
    depends_on:
      # ヘルスチェックを条件にする(推奨)
      db:
        condition: service_healthy
      redis:
        condition: service_started

networks

services:
  frontend:
    networks:
      - frontend-net

  backend:
    networks:
      - frontend-net
      - backend-net

  db:
    networks:
      - backend-net

networks:
  frontend-net:
  backend-net:

よく使うコマンド一覧

コマンド説明
docker compose up -dバックグラウンドで起動
docker compose down停止してコンテナを削除
docker compose down -vボリュームも含めて削除
docker compose ps実行中のコンテナ一覧
docker compose logs -fログをリアルタイム表示
docker compose logs app特定サービスのログ
docker compose exec app bashコンテナ内でコマンド実行
docker compose buildイメージを再ビルド
docker compose build --no-cacheキャッシュなしでビルド
docker compose pullイメージを最新に更新
docker compose restart再起動
docker compose stop停止(コンテナは残る)

実践的な構成例

Node.js + PostgreSQL + Redis

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      DATABASE_URL: postgresql://dev:dev@db:5432/myapp
      REDIS_URL: redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
    command: npm run dev

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: dev
      POSTGRES_PASSWORD: dev
      POSTGRES_DB: myapp
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dev"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  adminer:
    image: adminer
    ports:
      - "8080:8080"
    depends_on:
      - db

volumes:
  pgdata:

Dockerfile.dev の例

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

EXPOSE 3000
CMD ["npm", "run", "dev"]

ホットリロードを有効にする

開発環境ではソースコードの変更を即座に反映させたいものです。

services:
  app:
    volumes:
      # ソースコードをマウント
      - .:/app
      # node_modules はコンテナ内のものを使う
      - /app/node_modules
    command: npm run dev

Docker Compose Watch(v2.22+)

services:
  app:
    build: .
    develop:
      watch:
        # ソースコードの変更を同期
        - action: sync
          path: ./src
          target: /app/src
        # package.json が変わったらリビルド
        - action: rebuild
          path: ./package.json
docker compose watch

複数の Compose ファイルを使い分ける

# 開発用
docker compose -f compose.yml -f compose.dev.yml up

# テスト用
docker compose -f compose.yml -f compose.test.yml up

# 本番用
docker compose -f compose.yml -f compose.prod.yml up

compose.dev.yml(開発用オーバーライド)

services:
  app:
    volumes:
      - .:/app
    environment:
      - DEBUG=true
    command: npm run dev

compose.test.yml(テスト用オーバーライド)

services:
  app:
    environment:
      - NODE_ENV=test
    command: npm test

トラブルシューティング

ポートが競合する

# エラー: Bind for 0.0.0.0:5432 failed: port is already allocated
# 解決: ホスト側のポートを変更
ports:
  - "5433:5432"

ボリュームのパーミッション問題

services:
  app:
    user: "${UID:-1000}:${GID:-1000}"
    volumes:
      - .:/app

コンテナが起動直後に終了する

# ログを確認
docker compose logs app

# コンテナ内でデバッグ
docker compose run app sh

ビルドキャッシュが効かない

# キャッシュなしで再ビルド
docker compose build --no-cache

# すべてをクリーンアップ
docker compose down -v --rmi all

ベストプラクティス

  1. compose.yml はリポジトリにコミットする — チーム全員が同じ環境を再現できる
  2. シークレットは .env ファイルに書く.env.gitignore に追加
  3. ヘルスチェックを設定するdepends_oncondition: service_healthy が使える
  4. 名前付きボリュームを使う — データの永続化に必須
  5. 不要なイメージは Alpine 版を使う — イメージサイズが小さくなる

まとめ

Docker Compose を使えば、複雑な開発環境もYAMLファイル1つで管理できます。チーム全員が同じ環境を簡単に再現でき、「自分の環境では動く」問題から解放されます。


YAML ファイルのフォーマットが崩れた時は、AssistyのYAMLフォーマッターで整形できます。インデントの統一やバリデーションをブラウザ上で実行できます。