Docker Compose
作成日:
Docker container infrastructure Docker-Compose
複数のコンテナを定義・管理するためのツール。YAMLファイルでサービス構成を定義し、一括で起動・停止できます。
マルチサービス構成の基本
app + web の一般的な構成パターン
典型的な構成:
- web: リバースプロキシ(Nginx など)- 静的ファイル配信、SSL終端、リクエスト振り分け
- app: アプリケーションサーバー(Node.js、Python、PHP など)- ビジネスロジック処理
なぜ分けるのか?
- 責任分離: 静的ファイル配信とアプリロジックを分離
- パフォーマンス: Nginxが静的ファイルを高速配信、アプリは動的処理に専念
- スケーラビリティ: webとappを独立してスケール可能
- セキュリティ: 外部からの直接アクセスはwebのみ、appは内部ネットワークで保護
version: '3.8'
services:
# Webサーバー(フロントエンド)
web:
image: nginx:latest
restart: unless-stopped
ports:
- "80:80" # 外部からのアクセスはwebのみ
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- static-files:/usr/share/nginx/html
depends_on:
- app # appサービスが起動してからwebを起動
networks:
- frontend # 外部ネットワーク
- backend # 内部ネットワーク(appとの通信用)
# アプリケーションサーバー(バックエンド)
app:
image: node:16-alpine
restart: unless-stopped
# ポート公開なし(外部から直接アクセス不可)
expose:
- "3000" # 内部ネットワークでのみアクセス可能
environment:
- NODE_ENV=production
volumes:
- app-data:/app/data
- static-files:/app/public # 静的ファイルをwebと共有
networks:
- backend # 内部ネットワークのみ
- db-network # データベースとの通信用
# データベース
db:
image: postgres:13
restart: unless-stopped
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- db-network # アプリとの通信専用
secrets:
- db_password
# ネットワーク定義(サービス間通信の設定)
networks:
frontend: # 外部アクセス用
driver: bridge
backend: # web ↔ app 通信用
driver: bridge
internal: true # 外部からアクセス不可
db-network: # app ↔ db 通信用
driver: bridge
internal: true # 外部からアクセス不可
volumes:
app-data:
postgres-data:
static-files: # webとappで共有
secrets:
db_password:
external: true
サービス間通信の仕組み
1. ネットワークレベルでの通信制御
networks:
backend:
driver: bridge
internal: true # 外部からアクセス不可、内部通信のみ
2. サービス名での名前解決
- Docker Compose内ではサービス名がホスト名として機能
- 例:webサービスからappサービスへは
http://app:3000でアクセス
3. Nginxの設定例(web → app への通信)
# nginx.conf
server {
listen 80;
server_name localhost;
# 静的ファイル(CSS、JS、画像など)
location /static/ {
alias /usr/share/nginx/html/;
expires 30d;
}
# API リクエストをappサービスにプロキシ
location /api/ {
proxy_pass http://app:3000/; # サービス名'app'で通信
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# その他のリクエストもappにプロキシ
location / {
proxy_pass http://app:3000/; # サービス名'app'で通信
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
4. 通信フロー
外部クライアント → web:80/443 → app:3000 → db:5432
↑ ↑ ↑
外部公開 内部通信 内部通信
5. 依存関係とヘルスチェック
services:
web:
depends_on:
- app # app起動後にweb起動
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
app:
depends_on:
- db # db起動後にapp起動
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:3000/health"]
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
実際の運用での確認方法
サービス間通信のテスト:
# webコンテナからappへの通信確認
docker-compose exec web curl http://app:3000/health
# appコンテナからdbへの通信確認
docker-compose exec app nc -zv db 5432
# ネットワーク情報確認
docker network ls
docker network inspect <project_name>_backend
# サービス間のネットワーク接続確認
docker-compose exec web nslookup app
ログでの通信確認:
# 全サービスのログ
docker-compose logs -f
# 特定サービスのログ
docker-compose logs -f web
docker-compose logs -f app
# リアルタイムでの通信監視
docker-compose exec web tail -f /var/log/nginx/access.log
本番環境での重要な設定
命名規則
多くのオープンソースプロジェクトではケバブケース(kebab-case)が使用される
# 推奨:ケバブケース(kebab-case)
services:
web-app: # ハイフンで区切る
image: nginx
api-server: # 複数単語もハイフンで繋ぐ
image: node
worker-queue:
image: redis
volumes:
app-data: # ボリュームもケバブケース
log-files:
backup-storage:
networks:
frontend-net: # ネットワークもケバブケース
backend-net:
理由:
- 可読性: 単語の区切りが明確
- 一貫性: Kubernetesなど他のツールとの統一
- 標準的: 多くのOSSプロジェクトで採用
- URL安全: ハイフンはURL内で安全に使用可能
restart ポリシー
restart: unless-stopped は本番環境では必須の設定
restart ポリシーの種類:
- no: 再起動しない(デフォルト)
- always: 常に再起動(Docker起動時も含む)
- on-failure: 異常終了時のみ再起動
- unless-stopped: 手動で停止するまで再起動(推奨)
# 本番環境での推奨設定例
version: '3.8'
services:
web:
image: nginx:latest
restart: unless-stopped # 重要:自動復旧設定
ports:
- "80:80"
volumes:
- web-data:/usr/share/nginx/html
- /opt/config/nginx:/etc/nginx/conf.d:ro
depends_on:
- app
app:
image: myapp:latest
restart: unless-stopped # 重要:自動復旧設定
environment:
- NODE_ENV=production
volumes:
- app-data:/app/data
depends_on:
- db
db:
image: postgres:13
restart: unless-stopped # 重要:自動復旧設定
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- postgres-data:/var/lib/postgresql/data
secrets:
- db_password
volumes:
web-data:
app-data:
postgres-data:
secrets:
db_password:
external: true
なぜ unless-stopped が推奨なのか?
メリット:
- サーバー再起動時: 自動でコンテナが起動
- コンテナクラッシュ時: 自動で復旧
- 手動制御可能:
docker stopで明示的に停止可能 - 意図しない起動回避: 手動停止したコンテナは起動時に自動起動しない
always との違い:
# unless-stopped の場合
docker stop my-container # 手動停止
# → サーバー再起動時も起動しない
# always の場合
docker stop my-container # 手動停止
# → サーバー再起動時に自動起動してしまう
本番環境でのその他重要設定
services:
app:
image: myapp:latest
restart: unless-stopped
# リソース制限(重要)
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
memory: 256M
# ヘルスチェック(重要)
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# ログ設定
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# セキュリティ設定
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
ヘルスチェックの詳細設定
ヘルスチェックとは:
- コンテナの健全性を定期的に監視する仕組み
- サービスが正常に動作しているかを自動確認
- 異常時の自動復旧やロードバランサーからの除外に活用
設定パラメータ:
test: 実行するヘルスチェックコマンドinterval: チェック間隔(デフォルト: 30s)timeout: タイムアウト時間(デフォルト: 30s)retries: 失敗の許容回数(デフォルト: 3)start_period: 初回チェックまでの猶予時間(デフォルト: 0s)
サービス別ヘルスチェック例:
services:
# Webアプリケーション
web:
image: nginx:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# MySQL データベース
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secretpassword
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-uroot", "-p$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 5s
retries: 10
start_period: 60s
# PostgreSQL データベース
postgres:
image: postgres:13
environment:
POSTGRES_PASSWORD: secretpassword
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Redis
redis:
image: redis:6-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 3s
retries: 3
# Node.js API
api:
image: node:16-alpine
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
ヘルスチェック状態の確認:
# コンテナの健康状態確認
docker ps
# 詳細なヘルスチェック履歴
docker inspect <container_name> | grep -A 20 "Health"
# Docker Composeでの確認
docker-compose ps
ヘルスチェックのベストプラクティス:
- 軽量なチェック: 過度に重い処理は避ける
- 適切な間隔: あまり頻繁すぎるとリソース消費が大きい
- 依存関係を考慮: DBが起動してからAPIをチェック
- 適切なタイムアウト: ネットワーク遅延を考慮した設定
実際の運用例:
# 本番環境での起動
docker compose -f compose.yaml -f compose.production.yaml up -d
# サービス状態確認
docker-compose ps
# ログ確認
docker-compose logs -f --tail=100
# 特定サービスの再起動
docker-compose restart app
# 設定変更後の再デプロイ
docker-compose pull
docker-compose up -d
Docker Composeの停止・削除
# 基本的な停止(コンテナを停止、削除しない)
docker-compose stop
# 停止と削除(コンテナとネットワークを削除)
docker-compose down
# 特定のサービスのみ停止
docker-compose stop web
# ボリュームも含めて完全削除
docker-compose down -v
# イメージも削除(開発環境のクリーンアップ)
docker-compose down --rmi all
# 孤立したコンテナも削除
docker-compose down --remove-orphans
# 強制停止(緊急時)
docker-compose kill
# プロダクションファイル指定での停止
docker compose -f compose.yaml -f compose.production.yaml down
stopとdownの違い:
stop: コンテナを停止するが、コンテナとネットワークは残るdown: コンテナを停止し、コンテナとネットワークを削除する
本番環境での推奨手順:
# 1. まず状態確認
docker-compose ps
# 2. ログを確認(必要に応じて)
docker-compose logs
# 3. グレースフルシャットダウン
docker-compose down
# 4. 完全停止の確認
docker ps -a | grep <project_name>
関連トピック
- Docker - Dockerの基本概念
- Docker ボリューム - ボリュームの詳細