Docker Compose 基礎 (Compose Basics)
docker-compose.yml の構文と概念を体系的に理解し、services / volumes / networks を組み合わせたマルチコンテナアプリケーション環境を構築する基礎力を身につける。
Docker Compose 基礎 (Compose Basics)
docker-compose.yml の構文と概念を体系的に理解し、services / volumes / networks を組み合わせたマルチコンテナアプリケーション環境を構築する基礎力を身につける。
この章で学ぶこと
- docker-compose.yml の構文と基本構造 -- YAML 記法に基づく Compose ファイルの各セクション(services, volumes, networks)の役割と記法を理解する
- サービス定義とコンテナのライフサイクル管理 -- イメージ指定、ビルド設定、ポート公開、環境変数など、サービス定義の主要オプションを習得する
- ボリュームとネットワークによるデータ・通信の管理 -- コンテナ間のデータ永続化と内部通信の設計パターンを学ぶ
前提知識
このガイドを読む前に、以下の知識があると理解が深まります:
- 基本的なプログラミングの知識
- 関連する基礎概念の理解
1. Docker Compose とは
1.1 単一コンテナ vs Compose
+------------------------------------------------------------------+
| 単一コンテナ vs Docker Compose |
+------------------------------------------------------------------+
| |
| [単一コンテナ (docker run)] |
| $ docker run -d --name web -p 3000:3000 \ |
| -e DATABASE_URL=... \ |
| --network mynet myapp:latest |
| $ docker run -d --name db -p 5432:5432 \ |
| -v pgdata:/var/lib/postgresql/data \ |
| --network mynet postgres:16 |
| → コマンドが長い、管理が煩雑、再現性が低い |
| |
| [Docker Compose] |
| $ docker compose up -d |
| → 1コマンドで全サービス起動。設定は YAML ファイルで管理 |
| |
+------------------------------------------------------------------+
1.2 Docker Compose のアーキテクチャ
+------------------------------------------------------------------+
| Docker Compose の内部アーキテクチャ |
+------------------------------------------------------------------+
| |
| docker compose up |
| | |
| +-- compose.yml のパース & バリデーション |
| | | |
| | +-- YAML → 内部モデルへの変換 |
| | +-- 環境変数の展開 (.env ファイル含む) |
| | +-- 複数 Compose ファイルのマージ |
| | +-- プロファイルのフィルタリング |
| | |
| +-- 依存関係グラフの構築 |
| | | |
| | +-- depends_on の解析 |
| | +-- 循環依存の検出 |
| | +-- 起動順序の決定 |
| | |
| +-- リソースの作成 |
| | | |
| | +-- ネットワーク作成 (docker network create) |
| | +-- ボリューム作成 (docker volume create) |
| | +-- シークレット/コンフィグの準備 |
| | |
| +-- サービスの起動 |
| | |
| +-- イメージの pull または build |
| +-- コンテナ作成 (docker create) |
| +-- コンテナ起動 (docker start) |
| +-- ヘルスチェック待機 |
| +-- 依存サービスの起動 |
| |
+------------------------------------------------------------------+
1.3 プロジェクト名とコンテナ名の仕組み
Docker Compose はプロジェクト名をベースにリソースの名前を決定する。プロジェクト名は以下の優先順位で決まる:
# 1. -p / --project-name フラグ(最高優先度)
docker compose -p myproject up -d
# 2. COMPOSE_PROJECT_NAME 環境変数
export COMPOSE_PROJECT_NAME=myproject
docker compose up -d
# 3. compose.yml 内の name フィールド
# compose.yml
# name: myproject
# 4. compose.yml があるディレクトリ名(デフォルト)
# /home/user/my-app/ → プロジェクト名: my-appリソースの命名規則:
+------------------------------------------------------------------+
| プロジェクト名によるリソース命名 |
+------------------------------------------------------------------+
| |
| プロジェクト名: myproject |
| |
| コンテナ名: myproject-web-1, myproject-db-1 |
| ネットワーク名: myproject_default |
| ボリューム名: myproject_pgdata |
| |
| container_name で明示的に指定も可能: |
| services: |
| web: |
| container_name: my-web-server # 固定名 |
| # ※ container_name を指定すると |
| # スケール (--scale) が使えなくなる |
| |
+------------------------------------------------------------------+
1.4 Compose ファイルのバージョン
+------------------------------------------------------------------+
| Compose ファイル仕様の歴史 |
+------------------------------------------------------------------+
| バージョン | 特徴 | 推奨度 |
|------------------|--------------------------|-----------------|
| version: "2" | Docker Engine 統合前 | 非推奨 |
| version: "3" | Swarm 対応 | 非推奨 |
| version: "3.8" | 最終明示バージョン | 互換性用途のみ |
| (バージョン省略) | Compose Spec 準拠 | 推奨 (現在の標準) |
+------------------------------------------------------------------+
| |
| 現在は version キーを省略し、Compose Specification に |
| 準拠するのが推奨。Docker Compose V2 が自動判定する。 |
| |
+------------------------------------------------------------------+
2. docker-compose.yml の基本構造
2.1 全体構造
# docker-compose.yml
# (version は省略推奨)
# サービス定義 (コンテナの設定)
services:
web:
image: node:20-alpine
# ... 設定
db:
image: postgres:16-alpine
# ... 設定
# ボリューム定義 (データ永続化)
volumes:
pgdata:
driver: local
# ネットワーク定義 (コンテナ間通信)
networks:
backend:
driver: bridge
# シークレット定義 (機密情報)
secrets:
db_password:
file: ./secrets/db_password.txt
# 設定定義 (設定ファイル)
configs:
nginx_conf:
file: ./nginx/nginx.conf2.2 Compose ファイルの階層図
+------------------------------------------------------------------+
| docker-compose.yml の構造 |
+------------------------------------------------------------------+
| |
| docker-compose.yml |
| | |
| +-- services: ← コンテナ定義 (必須) |
| | +-- web: |
| | | +-- image / build |
| | | +-- ports |
| | | +-- environment |
| | | +-- volumes |
| | | +-- networks |
| | | +-- depends_on |
| | | +-- restart |
| | +-- db: |
| | +-- ... |
| | |
| +-- volumes: ← ボリューム定義 (任意) |
| | +-- pgdata: |
| | |
| +-- networks: ← ネットワーク定義 (任意) |
| | +-- backend: |
| | |
| +-- secrets: ← シークレット定義 (任意) |
| +-- configs: ← 設定ファイル定義 (任意) |
| |
+------------------------------------------------------------------+
3. services の詳細
3.1 イメージ指定 vs ビルド
services:
# パターン 1: 既存イメージを使用
db:
image: postgres:16-alpine
# パターン 2: Dockerfile からビルド
web:
build:
context: . # ビルドコンテキスト
dockerfile: Dockerfile # Dockerfile パス (デフォルト: Dockerfile)
args: # ビルド引数
NODE_ENV: production
target: runner # マルチステージの対象ステージ
cache_from:
- myapp:latest
image: myapp:latest # ビルド後のタグ名
# パターン 3: 簡易ビルド
api:
build: ./api # context のみ指定 (Dockerfile は自動検出)3.2 ポート公開
services:
web:
ports:
# ホスト:コンテナ
- "3000:3000" # localhost:3000 → コンテナ:3000
- "443:443"
# ホスト IP 指定
- "127.0.0.1:3000:3000" # localhost のみ (外部からアクセス不可)
# ホストポートをランダムに割り当て
- "3000" # ランダムポート → コンテナ:3000
# プロトコル指定
- "6379:6379/tcp"
# コンテナ間のみ公開 (ホストからはアクセス不可)
expose:
- "3000"3.3 環境変数
services:
web:
environment:
# キー=値 形式
NODE_ENV: production
DATABASE_URL: postgresql://postgres:postgres@db:5432/myapp
# 値なし = ホストの環境変数を引き継ぐ
API_KEY:
# .env ファイルから読み込み
env_file:
- .env
- .env.local # 後のファイルが優先3.4 ボリュームマウント
services:
web:
volumes:
# 名前付きボリューム
- node_modules:/app/node_modules
# バインドマウント (ホストディレクトリ)
- ./src:/app/src
# 読み取り専用
- ./config:/app/config:ro
# tmpfs (メモリ上)
- type: tmpfs
target: /tmp
tmpfs:
size: 100000000 # 100MB
# 詳細構文
- type: bind
source: ./data
target: /app/data
consistency: cached # macOS パフォーマンス改善3.5 再起動ポリシー
services:
web:
restart: unless-stopped
# no : 再起動しない (デフォルト)
# always : 常に再起動
# on-failure : 異常終了時のみ再起動
# unless-stopped: 手動停止以外は再起動3.6 depends_on と起動順序制御
services:
web:
build: .
depends_on:
db:
condition: service_healthy # ヘルスチェック通過後に起動
restart: true # db 再起動時に web も再起動
redis:
condition: service_started # コンテナ起動のみ確認
migrations:
condition: service_completed_successfully # 正常終了後に起動
migrations:
build: .
command: ["npm", "run", "migrate"]
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5+------------------------------------------------------------------+
| depends_on の condition 一覧 |
+------------------------------------------------------------------+
| |
| condition | 説明 |
| ----------------------- | ------------------------------------- |
| service_started | コンテナが起動したら (デフォルト) |
| service_healthy | ヘルスチェックが healthy になったら |
| service_completed_ | コンテナが正常終了 (exit 0) したら |
| successfully | |
| |
| 起動順序の例: |
| db (healthy) → migrations (completed) → web (start) |
| |
| ※ service_healthy には healthcheck の定義が必須 |
| ※ service_completed_successfully は |
| マイグレーションやシード処理で活用 |
| |
+------------------------------------------------------------------+
3.7 リソース制限
services:
web:
deploy:
resources:
limits:
cpus: "1.0" # CPU コア数の上限
memory: 512M # メモリ上限
reservations:
cpus: "0.25" # 予約 CPU
memory: 128M # 予約メモリ
db:
deploy:
resources:
limits:
cpus: "2.0"
memory: 1G
reservations:
cpus: "0.5"
memory: 256M
# OOM Killer の調整
oom_kill_disable: false # OOM Killer を無効にしない(推奨)
oom_score_adj: -500 # OOM スコアの調整(低い = kill されにくい)3.8 ログ設定
services:
web:
logging:
driver: json-file # デフォルトのログドライバー
options:
max-size: "10m" # ログファイルの最大サイズ
max-file: "3" # ローテーション数
compress: "true" # 圧縮の有効化
tag: "{{.Name}}" # ログタグ
# syslog に送信
api:
logging:
driver: syslog
options:
syslog-address: "tcp://logserver:514"
syslog-facility: daemon
tag: "api-service"
# ログを無効化(大量ログを出すサービス向け)
load-test:
logging:
driver: none3.9 ヘルスチェック
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s # チェック間隔
timeout: 10s # タイムアウト
retries: 3 # リトライ回数
start_period: 40s # 起動猶予期間(この間の失敗はカウントしない)
start_interval: 5s # 起動中のチェック間隔 (Compose v2.20+)
# シェルコマンドを使ったヘルスチェック
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d myapp"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
# ヘルスチェックを無効化(デフォルトのヘルスチェックがあるイメージ)
custom-service:
healthcheck:
disable: true+------------------------------------------------------------------+
| ヘルスチェックのステートマシン |
+------------------------------------------------------------------+
| |
| コンテナ起動 |
| | |
| v |
| [starting] ← start_period の間はここに留まる |
| | |
| +-- チェック成功 → [healthy] |
| | | |
| | +-- チェック失敗 (retries 回) → [unhealthy]|
| | | |
| | +-- チェック成功 → [healthy] (ループ) |
| | |
| +-- start_period 経過後もチェック失敗 → [unhealthy] |
| |
| ※ unhealthy になっても restart ポリシーがないと再起動しない |
| ※ depends_on + service_healthy で他サービスの起動をブロック |
| |
+------------------------------------------------------------------+
4. volumes (ボリューム)
4.1 ボリュームの種類
+------------------------------------------------------------------+
| ボリュームの種類と特徴 |
+------------------------------------------------------------------+
| |
| [名前付きボリューム] (Named Volume) |
| volumes: |
| pgdata: |
| driver: local |
| → Docker が管理。docker volume ls で確認可能 |
| → コンテナ間で共有可能。永続化が保証される |
| → macOS/Windows でも高速 (Docker VM 内) |
| |
| [バインドマウント] (Bind Mount) |
| volumes: |
| - ./src:/app/src |
| → ホストのディレクトリをそのままマウント |
| → 開発中のソースコード共有に最適 |
| → macOS/Windows では I/O が遅い場合がある |
| |
| [tmpfs] |
| tmpfs: |
| - /tmp |
| → メモリ上に作成。コンテナ停止で消失 |
| → 一時ファイルやキャッシュに最適 |
| |
+------------------------------------------------------------------+
4.2 ボリュームの定義
volumes:
# シンプルな定義
pgdata:
# ドライバー指定
mysql_data:
driver: local
# 外部ボリューム (docker volume create で事前作成)
shared_data:
external: true
# ドライバーオプション
nfs_data:
driver: local
driver_opts:
type: nfs
o: addr=192.168.1.100,rw
device: ":/exports/data"5. networks (ネットワーク)
5.1 ネットワークの仕組み
+------------------------------------------------------------------+
| Compose ネットワークの仕組み |
+------------------------------------------------------------------+
| |
| docker compose up 実行時: |
| → デフォルトで {プロジェクト名}_default ネットワークが作成される |
| → 全サービスがこのネットワークに接続 |
| → サービス名で DNS 解決が可能 |
| |
| +--- default ネットワーク -------------------------+ |
| | | |
| | [web] [db] | |
| | curl http://db:5432 <---> PostgreSQL | |
| | curl http://redis:6379 <---> [redis] | |
| | | |
| +-------------------------------------------------+ |
| |
| ※ サービス名 = DNS ホスト名 として自動解決される |
| |
+------------------------------------------------------------------+
5.2 ネットワークの使い分け
services:
web:
networks:
- frontend
- backend
api:
networks:
- backend
db:
networks:
- backend # web からは直接アクセスできない
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 外部からのアクセスを遮断5.3 ネットワーク比較
| 項目 | デフォルト | カスタム bridge | internal | host |
|---|---|---|---|---|
| 自動作成 | あり | なし | なし | N/A |
| コンテナ間通信 | 全サービス | 指定サービスのみ | 指定サービスのみ | ホストネットワーク |
| 外部アクセス | ports で公開 | ports で公開 | 不可 | ポート直接 |
| DNS 解決 | サービス名 | サービス名 | サービス名 | ホスト名 |
| セキュリティ | 低 | 中 | 高 | 低 |
| 用途 | 小規模 | 一般 | DB/内部API | パフォーマンス |
5.4 ネットワークの詳細設定
networks:
# カスタムサブネット指定
backend:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
gateway: 172.28.0.1
# DNS 設定
custom_dns:
driver: bridge
driver_opts:
com.docker.network.bridge.name: custom0
services:
web:
networks:
backend:
ipv4_address: 172.28.0.10 # 固定 IP アドレス
aliases:
- web.local # 追加の DNS エイリアス
- frontend.local
api:
networks:
backend:
ipv4_address: 172.28.0.20
aliases:
- api.local
# DNS 設定
dns:
- 8.8.8.8
- 8.8.4.4
dns_search:
- example.com
# /etc/hosts に追加
extra_hosts:
- "host.docker.internal:host-gateway" # ホストマシンへのアクセス
- "api.external.com:192.168.1.100" # 外部サービスの解決5.5 ネットワーク分離パターン
+------------------------------------------------------------------+
| マイクロサービスのネットワーク分離設計 |
+------------------------------------------------------------------+
| |
| [Internet] |
| | |
| v |
| +--- public ネットワーク ---+ |
| | [nginx/traefik] | |
| | (リバースプロキシ) | |
| +-----|-------|-------------+ |
| | | |
| v v |
| +--- frontend ネットワーク ---+ |
| | [web-app] [admin-app] | |
| +-----|-------|-----|--------+ |
| | | | |
| v v v |
| +--- api ネットワーク ------+ |
| | [api-gateway] | |
| | | | | |
| | v v | |
| | [user-svc] [order-svc] | |
| +----|---------|------------+ |
| | | |
| v v |
| +--- data ネットワーク (internal) ---+ |
| | [postgres] [redis] [rabbitmq] | |
| | ※ 外部から直接アクセス不可 | |
| +-----------------------------------+ |
| |
+------------------------------------------------------------------+
6. secrets と configs
6.1 シークレットの定義と利用
# docker-compose.yml
services:
db:
image: postgres:16-alpine
secrets:
- db_password
- db_user
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_USER_FILE: /run/secrets/db_user
web:
build: .
secrets:
- source: db_password # シークレット名
target: database_password # コンテナ内のファイル名
uid: "1000" # ファイルの所有者 UID
gid: "1000" # ファイルの所有者 GID
mode: 0440 # ファイルのパーミッション
secrets:
# ファイルベースのシークレット
db_password:
file: ./secrets/db_password.txt
# 環境変数ベースのシークレット
db_user:
environment: POSTGRES_USER # ホストの環境変数から取得+------------------------------------------------------------------+
| シークレットの仕組み |
+------------------------------------------------------------------+
| |
| ホスト コンテナ |
| ./secrets/db_password.txt --> /run/secrets/db_password |
| |
| ※ シークレットは tmpfs にマウントされる |
| ※ 環境変数と異なり docker inspect で値が見えない |
| ※ ファイルとしてアクセスするためアプリ側の対応が必要 |
| |
| PostgreSQL の _FILE サフィックス対応: |
| POSTGRES_PASSWORD_FILE=/run/secrets/db_password |
| → ファイルの内容を POSTGRES_PASSWORD として認識 |
| |
+------------------------------------------------------------------+
6.2 configs の定義と利用
services:
nginx:
image: nginx:alpine
configs:
- source: nginx_conf
target: /etc/nginx/nginx.conf # コンテナ内のパス
uid: "0"
gid: "0"
mode: 0444
prometheus:
image: prom/prometheus:v2.51.0
configs:
- source: prometheus_conf
target: /etc/prometheus/prometheus.yml
configs:
nginx_conf:
file: ./nginx/nginx.conf
prometheus_conf:
file: ./prometheus/prometheus.yml7. 基本コマンド
7.1 よく使うコマンド
# 起動
docker compose up -d # バックグラウンドで全サービス起動
docker compose up web db # 指定サービスのみ起動
docker compose up --build # ビルドしてから起動
# 停止
docker compose stop # サービス停止 (コンテナ保持)
docker compose down # サービス停止 + コンテナ削除
docker compose down -v # + ボリュームも削除
docker compose down --rmi all # + イメージも削除
# 状態確認
docker compose ps # サービス一覧
docker compose logs # ログ表示
docker compose logs -f web # 特定サービスのログをフォロー
docker compose top # プロセス一覧
# 実行
docker compose exec web bash # 起動中コンテナでコマンド実行
docker compose run web npm test # 新しいコンテナでコマンド実行
# その他
docker compose config # 設定の検証 & 展開結果表示
docker compose pull # イメージを最新に更新
docker compose build # サービスのビルドのみ7.2 コマンドフロー図
+------------------------------------------------------------------+
| docker compose コマンドフロー |
+------------------------------------------------------------------+
| |
| docker compose up -d |
| | |
| +-- ネットワーク作成 (なければ) |
| +-- ボリューム作成 (なければ) |
| +-- イメージ pull/build (なければ) |
| +-- コンテナ作成 & 起動 |
| +-- ヘルスチェック待機 (設定されていれば) |
| |
| docker compose down |
| | |
| +-- コンテナ停止 |
| +-- コンテナ削除 |
| +-- ネットワーク削除 |
| +-- (ボリュームは保持。-v で削除) |
| |
+------------------------------------------------------------------+
7.3 コマンドの実行パターン比較
+------------------------------------------------------------------+
| exec vs run の違い |
+------------------------------------------------------------------+
| |
| docker compose exec web bash |
| → 起動中のコンテナに接続 |
| → コンテナの環境変数・ネットワークをそのまま使用 |
| → コンテナが停止すると使えない |
| → ファイル変更は永続(コンテナ再作成まで) |
| |
| docker compose run web npm test |
| → 新しいコンテナを作成して実行 |
| → ポートマッピングはデフォルトで無効 (--service-ports で有効化) |
| → depends_on のサービスも起動される |
| → 終了後にコンテナが残る (--rm で自動削除) |
| |
| 使い分けガイド: |
| +---------------------------+-----------------------------------+|
| | ユースケース | コマンド ||
| +---------------------------+-----------------------------------+|
| | デバッグ (シェル接続) | exec web bash ||
| | テスト実行 | run --rm web npm test ||
| | マイグレーション | run --rm web npm run migrate ||
| | 一回限りのスクリプト | run --rm web node script.js ||
| | データベースクライアント | exec db psql -U postgres ||
| +---------------------------+-----------------------------------+|
| |
+------------------------------------------------------------------+
8. 実践的な構成例
8.1 Web アプリケーション + DB + Redis
# docker-compose.yml
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://postgres:postgres@db:5432/myapp
REDIS_URL: redis://redis:6379
volumes:
- .:/app
- node_modules:/app/node_modules
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: myapp
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
pgdata:
node_modules:8.2 Django + PostgreSQL + Nginx
# docker-compose.yml
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- static_volume:/app/staticfiles:ro
- media_volume:/app/media:ro
depends_on:
web:
condition: service_healthy
restart: unless-stopped
web:
build:
context: .
target: production
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/media
environment:
DATABASE_URL: postgresql://postgres:${DB_PASSWORD}@db:5432/django_app
DJANGO_SETTINGS_MODULE: config.settings.production
SECRET_KEY: ${DJANGO_SECRET_KEY}
ALLOWED_HOSTS: ${ALLOWED_HOSTS:-localhost}
expose:
- "8000"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health/')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
environment:
POSTGRES_DB: django_app
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d django_app"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
# マイグレーション(起動時に一度だけ実行)
migrate:
build:
context: .
target: production
command: python manage.py migrate --noinput
environment:
DATABASE_URL: postgresql://postgres:${DB_PASSWORD}@db:5432/django_app
depends_on:
db:
condition: service_healthy
# 静的ファイル収集(起動時に一度だけ実行)
collectstatic:
build:
context: .
target: production
command: python manage.py collectstatic --noinput
volumes:
- static_volume:/app/staticfiles
depends_on:
migrate:
condition: service_completed_successfully
volumes:
pgdata:
static_volume:
media_volume:8.3 マイクロサービス構成
# docker-compose.yml
services:
# API ゲートウェイ
gateway:
build: ./gateway
ports:
- "8080:8080"
environment:
USER_SERVICE_URL: http://user-service:3001
ORDER_SERVICE_URL: http://order-service:3002
PRODUCT_SERVICE_URL: http://product-service:3003
networks:
- frontend
- backend
depends_on:
user-service:
condition: service_healthy
order-service:
condition: service_healthy
product-service:
condition: service_healthy
restart: unless-stopped
# ユーザーサービス
user-service:
build: ./services/user
expose:
- "3001"
environment:
DATABASE_URL: postgresql://postgres:postgres@user-db:5432/users
REDIS_URL: redis://redis:6379/0
networks:
- backend
- data
depends_on:
user-db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3001/health"]
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
# 注文サービス
order-service:
build: ./services/order
expose:
- "3002"
environment:
DATABASE_URL: postgresql://postgres:postgres@order-db:5432/orders
RABBITMQ_URL: amqp://guest:guest@rabbitmq:5672
networks:
- backend
- data
depends_on:
order-db:
condition: service_healthy
rabbitmq:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3002/health"]
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
# 商品サービス
product-service:
build: ./services/product
expose:
- "3003"
environment:
DATABASE_URL: postgresql://postgres:postgres@product-db:5432/products
networks:
- backend
- data
depends_on:
product-db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3003/health"]
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
# データベース群
user-db:
image: postgres:16-alpine
volumes:
- user_pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: users
POSTGRES_PASSWORD: postgres
networks:
- data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
order-db:
image: postgres:16-alpine
volumes:
- order_pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: orders
POSTGRES_PASSWORD: postgres
networks:
- data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
product-db:
image: postgres:16-alpine
volumes:
- product_pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: products
POSTGRES_PASSWORD: postgres
networks:
- data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
# メッセージキュー
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- "15672:15672" # 管理画面(開発用)
expose:
- "5672"
volumes:
- rabbitmq_data:/var/lib/rabbitmq
networks:
- data
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 10s
timeout: 10s
retries: 5
restart: unless-stopped
# キャッシュ
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
networks:
frontend:
driver: bridge
backend:
driver: bridge
data:
driver: bridge
internal: true # 外部アクセス不可
volumes:
user_pgdata:
order_pgdata:
product_pgdata:
rabbitmq_data:
redis_data:8.4 環境変数と .env ファイルの管理
# .env (docker compose が自動読み込み)
COMPOSE_PROJECT_NAME=myapp
DB_PASSWORD=secure_password_here
DJANGO_SECRET_KEY=your-secret-key
ALLOWED_HOSTS=localhost,example.com
NODE_ENV=production# docker-compose.yml での環境変数の展開
services:
web:
image: myapp:${APP_VERSION:-latest} # デフォルト値付き
environment:
DB_HOST: ${DB_HOST:?DB_HOST is required} # 未設定ならエラー
DB_PORT: ${DB_PORT:-5432} # 未設定ならデフォルト
NODE_ENV: ${NODE_ENV} # .env から読み込み+------------------------------------------------------------------+
| 環境変数の優先順位 (高 → 低) |
+------------------------------------------------------------------+
| |
| 1. docker compose run -e で渡した値 |
| 2. シェルの環境変数 (export した値) |
| 3. compose.yml の environment セクション |
| 4. --env-file で指定したファイル |
| 5. compose.yml の env_file で指定したファイル |
| 6. Dockerfile の ENV 命令 |
| |
| ※ .env ファイルは compose.yml 内の変数展開 (${VAR}) に使用 |
| ※ env_file はコンテナの環境変数に直接設定 |
| ※ .env と env_file は別物であることに注意 |
| |
+------------------------------------------------------------------+
アンチパターン
アンチパターン 1: latest タグの使用
# NG: バージョン未固定
services:
db:
image: postgres:latest # どのバージョンが来るかわからない
redis:
image: redis # タグ省略 = latest
# OK: バージョンを明示的に固定
services:
db:
image: postgres:16-alpine # メジャーバージョン + バリアント
redis:
image: redis:7-alpine問題点: latest はイメージ更新のたびに異なるバージョンが pull される可能性があり、チームメンバー間や CI/CD と環境差異が生じる。PostgreSQL のメジャーバージョンアップは破壊的変更を含むことが多く、意図しないアップグレードでデータ破損のリスクもある。
アンチパターン 2: ホストネットワークモードの乱用
# NG: ホストネットワークで全ポートを露出
services:
db:
image: postgres:16
network_mode: host # 全ポートがホストに直接公開
# OK: 必要なポートだけを公開
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432" # localhost のみに公開問題点: network_mode: host はコンテナのネットワーク分離を完全に無効化する。DB やキャッシュサーバーが外部ネットワークから直接アクセス可能になり、セキュリティリスクが増大する。
アンチパターン 3: depends_on を condition なしで使う
# NG: コンテナ起動のみ確認(サービス準備完了を待たない)
services:
web:
build: .
depends_on:
- db # db コンテナが起動したら即 web を起動
db:
image: postgres:16-alpine
# ヘルスチェックなし
# -> PostgreSQL が接続受付前に web が起動し、接続エラーが発生
# OK: ヘルスチェック + condition で準備完了を待つ
services:
web:
build: .
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5問題点: depends_on のデフォルト (service_started) はコンテナの起動のみを確認する。データベースが実際にクエリを受け付けられる状態になるまでには数秒かかるため、アプリケーションが起動直後に接続エラーを起こす。アプリ側のリトライロジックだけに頼るのではなく、Compose のヘルスチェック連携を活用すべきである。
アンチパターン 4: ボリュームのバックアップを考慮しない
# NG: バックアップ手段のない名前付きボリューム
services:
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
# -> docker compose down -v でデータ完全消失
# OK: バックアップスクリプトを用意
# backup.sh
# docker compose exec db pg_dump -U postgres myapp > backup_$(date +%Y%m%d).sql
# より安全な構成: バックアップ用のサービスを追加
services:
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
backup:
image: postgres:16-alpine
volumes:
- ./backups:/backups
entrypoint: /bin/sh
command: >
-c "pg_dump -h db -U postgres myapp > /backups/backup_$$(date +%Y%m%d_%H%M%S).sql"
depends_on:
db:
condition: service_healthy
profiles:
- backup # docker compose --profile backup run backup で手動実行
volumes:
pgdata:問題点: 名前付きボリュームはコンテナのライフサイクルとは独立して存在するが、docker compose down -v や docker volume prune で削除される。本番データや重要なデータを扱う場合は、定期的なバックアップの仕組みを必ず用意する。
アンチパターン 5: 環境変数でシークレットを管理する
# NG: パスワードが compose ファイルにハードコード
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: my_secret_password # Git にコミットされる
web:
build: .
environment:
DB_PASSWORD: my_secret_password # docker inspect で見える
# OK: .env ファイル + secrets を活用
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
web:
build: .
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt # .gitignore に追加問題点: 環境変数にシークレットをハードコードすると Git リポジトリにコミットされ、docker inspect でも値が見える。.env ファイルを使う場合は .gitignore に追加し、シークレットが必要な場合は Docker の secrets 機能を使うべきである。
FAQ
Q1: docker-compose と docker compose (ハイフンなし) の違いは何ですか?
A: docker-compose は Python 製の Compose V1 (スタンドアロンバイナリ)、docker compose は Go 製の Compose V2 (Docker CLI プラグイン)。V1 は 2023 年 6 月に EOL を迎えており、現在は V2 の docker compose を使うべき。機能的にはほぼ互換だが、V2 の方が高速で、docker compose サブコマンドとして Docker CLI に統合されている。
Q2: depends_on を設定すればサービスの起動順序は保証されますか?
A: depends_on はコンテナの起動順序のみを制御し、サービスが「準備完了」になったことは保証しない。例えば PostgreSQL コンテナが起動してから実際に接続を受け付けるまでには数秒かかる。depends_on に condition: service_healthy を指定し、ヘルスチェックと組み合わせることで、サービスが実際に利用可能になるまで待機できる。
Q3: 開発用と本番用で Compose ファイルを分けるべきですか?
A: はい。docker-compose.yml (共通/開発用) と docker-compose.prod.yml (本番用オーバーライド) に分けるのが一般的。docker compose -f docker-compose.yml -f docker-compose.prod.yml up のように複数ファイルを指定すると、後のファイルで前のファイルの設定を上書きできる。Compose V2 では compose.yml と compose.override.yml を自動的にマージする機能もある。
Q4: Compose で特定のサービスだけを再ビルドして更新するには?
A: docker compose up -d --build web のようにサービス名を指定する。--build フラグを付けると、起動前にイメージを再ビルドする。--no-deps を追加すると、依存サービスの再起動を防げる: docker compose up -d --build --no-deps web。イメージの再ビルドだけを行いたい場合は docker compose build web を使う。
Q5: macOS で Compose のバインドマウントが遅いのですが、対策はありますか?
A: macOS (Docker Desktop for Mac) ではバインドマウントの I/O パフォーマンスがネイティブに比べて遅い。以下の対策がある:
- VirtioFS を使う: Docker Desktop の設定で
VirtioFSを有効化する(デフォルトで有効な場合が多い)。gRPC FUSE より大幅に高速 - ボリュームの分離:
node_modulesやvendorなどの依存関係ディレクトリは名前付きボリュームに分離する - Synchronized file shares (Docker Desktop 4.27+): ファイル同期を最適化する機能
# macOS パフォーマンス改善例
services:
web:
volumes:
- .:/app # ソースコード
- node_modules:/app/node_modules # 名前付きボリュームで分離
volumes:
node_modules:Q6: docker compose watch とは何ですか?
A: Docker Compose v2.22+ で導入された機能で、ファイル変更を検知して自動的にアクションを実行する。ホットリロードやオートリビルドを Compose レベルで管理できる。
services:
web:
build: .
develop:
watch:
- action: sync # ファイルをコンテナに同期
path: ./src
target: /app/src
- action: rebuild # イメージを再ビルド
path: package.json
- action: sync+restart # 同期してコンテナ再起動
path: ./config
target: /app/configdocker compose watch で起動すると、ファイル変更に応じて sync(ファイル同期)、rebuild(イメージ再ビルド + コンテナ再作成)、sync+restart(ファイル同期 + コンテナ再起動)が自動的に実行される。
Q7: 複数の Compose ファイルを使い分けるにはどうすればよいですか?
A: 複数の Compose ファイルをマージする方法がいくつかある:
# 1. -f フラグで明示的にファイルを指定(後のファイルで上書き)
docker compose -f compose.yml -f compose.prod.yml up -d
# 2. compose.override.yml は自動的にマージされる
# compose.yml ← ベース設定
# compose.override.yml ← 開発用の上書き設定(自動マージ)
# 3. COMPOSE_FILE 環境変数
export COMPOSE_FILE=compose.yml:compose.prod.yml
docker compose up -d
# 4. include (Compose v2.20+)
# compose.yml
# include:
# - path: ./monitoring/compose.yml
# - path: ./logging/compose.yml# compose.yml (ベース)
services:
web:
build: .
ports:
- "3000:3000"
# compose.override.yml (開発用 - 自動マージ)
services:
web:
volumes:
- .:/app
environment:
NODE_ENV: development
# compose.prod.yml (本番用 - 明示指定)
services:
web:
restart: always
environment:
NODE_ENV: production
deploy:
resources:
limits:
memory: 512Mまとめ
| 項目 | 要点 |
|---|---|
| Compose ファイル | version キーは省略。Compose Specification 準拠が現在の標準 |
| services | コンテナの定義。image / build / ports / environment / volumes が基本 |
| volumes | 名前付き Volume を推奨。DB データの永続化に必須 |
| networks | デフォルトでサービス名による DNS 解決。分離が必要なら明示定義 |
| secrets | 機密情報はシークレットで管理。環境変数よりも安全 |
| configs | 設定ファイルのマウント。nginx.conf や prometheus.yml 等 |
| depends_on | condition: service_healthy でヘルスチェック連携が重要 |
| healthcheck | サービス準備完了の検知に必須。DB は pg_isready、HTTP は curl |
| リソース制限 | deploy.resources で CPU/メモリの上限と予約を設定 |
| ログ管理 | logging で max-size/max-file を設定してディスク枯渇を防止 |
| コマンド | up -d / down / logs -f / exec が日常の基本操作 |
| イメージタグ | latest を避け、メジャーバージョン + バリアントを明示 |
| V1 vs V2 | docker compose (V2, CLI プラグイン) を使用。V1 は EOL |
| 環境変数 | .env ファイルで管理。シークレットのハードコードは避ける |
| ファイル分割 | compose.override.yml で開発/本番の設定を分離 |
次に読むべきガイド
- Compose 応用 -- プロファイル、depends_on、healthcheck、環境変数の高度な使い方
- Compose 開発ワークフロー -- ホットリロード、デバッグ、CI 統合
- ローカルサービスの Docker 化 -- DB / Redis / MailHog の実践的な Compose 構成
参考文献
- Docker Compose 公式リファレンス -- https://docs.docker.com/compose/compose-file/ -- Compose ファイル仕様の完全なリファレンス
- Compose Specification -- https://compose-spec.io/ -- Docker Compose の公式仕様 (GitHub)
- Docker 公式チュートリアル -- https://docs.docker.com/compose/gettingstarted/ -- Compose のクイックスタートガイド
- Docker Compose Networking -- https://docs.docker.com/compose/networking/ -- Compose のネットワーク設定の詳細ガイド
- Docker Compose Environment Variables -- https://docs.docker.com/compose/environment-variables/ -- 環境変数の設定方法と優先順位
- Docker Compose Watch -- https://docs.docker.com/compose/file-watch/ -- ファイル監視による自動同期・リビルド機能のドキュメント
- Awesome Docker Compose -- https://github.com/docker/awesome-compose -- Docker 公式の Compose サンプル集