Docker Composeは本番環境で使えるのか?
「Docker Composeって開発環境専用のツールじゃないの?」という疑問を持つ方は少なくありません。結論から言えば、Docker Composeは本番環境でも十分に使えます。特に中小規模のシステムでは、複雑なツールより、シンプルで管理しやすいDocker Composeの方が適しています。
Docker Composeの適用範囲を正しく理解する
Docker Composeが「開発専用」という誤解が広まった背景には、大規模システムの事例でKubernetesが紹介されることが多く、「本番環境=Kubernetes」というイメージが定着したことがあります。しかし実際には、システムの規模や要件によって適切なツールは異なります。
Docker Composeが適している場面:
- 単一サーバーまたは少数のサーバーで運用するシステム
- 月間数万〜数十万PV程度のWebサイト
- 社内向けの業務システムや管理ツール
- IT担当者が1〜3名程度の組織
Kubernetesを検討すべき場面:
- 複数サーバーにまたがる大規模分散システム
- 自動スケーリングが頻繁に必要なシステム
- 専任のインフラエンジニアチームがいる組織
中小企業にDocker Composeが適している理由は3つあります。学習コストの低さ(数日で基本運用が可能)、運用コストの削減(1台のVPSで運用可能)、トラブルシューティングの容易さ(設定ファイルを見れば原因を特定しやすい)です。月間10万PV程度のWebサービスなら、Docker Composeで十分に安定稼働できます。
開発環境と本番環境の設定を分離する
Docker Composeを本番環境で使う際の最初のステップは、環境ごとの設定を適切に分離することです。同じ設定を両環境で使うと、セキュリティリスクや予期しない動作の原因になります。
複数のComposeファイルによる環境管理
Docker Composeは複数のYAMLファイルを自動的にマージする機能があり、これを活用して環境を分離します。
推奨ファイル構成:
project/
├── docker-compose.yml # 基本設定(共通)
├── docker-compose.override.yml # 開発環境用(自動読み込み)
├── docker-compose.prod.yml # 本番環境用
└── .env.example # 環境変数テンプレート
docker-compose.yml(基本設定):
version: '3.8'
services:
web:
image: myapp:${APP_VERSION}
networks:
- app-network
depends_on:
- db
db:
image: postgres:14
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
volumes:
db-data:
docker-compose.override.yml(開発環境):
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- ./src:/app/src # ホットリロード用
environment:
- NODE_ENV=development
db:
ports:
- "5432:5432"
environment:
- POSTGRES_PASSWORD=devpassword
docker-compose.prod.yml(本番環境):
version: '3.8'
services:
web:
restart: always
environment:
- NODE_ENV=production
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
restart: always
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
開発環境ではdocker-compose upだけで起動でき、本番環境では以下のコマンドを使います。
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
環境変数による機密情報の管理
パスワードやAPIキーは.envファイルで管理し、Gitにコミットしません。
.env.example(テンプレート):
APP_VERSION=1.0.0
DB_PASSWORD=your_secure_password_here
SECRET_KEY=your_secret_key_here
.gitignore:
.env
.env.*
!.env.example
本番環境では、サーバー上で.envファイルを作成し、権限を制限します。
cp .env.example .env
vi .env # 実際の値を設定
chmod 600 .env
本番環境向けの必須設定
本番環境でDocker Composeを安全に運用するには、開発環境とは異なる設定が必要です。
開発環境の設定を削除する
以下の設定は本番環境から削除します。
- ソースコードのボリュームマウント(
./src:/app/src) - 内部サービスのポート公開(データベースなど)
- デバッグモードの環境変数
また、イメージタグはlatestではなく具体的なバージョン(myapp:1.2.3)を指定します。
自動再起動の設定
本番環境で最も重要な設定の一つがrestartポリシーです。
services:
web:
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
restart: alwaysにより、コンテナのクラッシュやサーバー再起動時に自動的に復旧します。ヘルスチェックと組み合わせることで、起動失敗の無限ループを防げます。
リソース制限の設定
リソース制限がないと、メモリリークでサーバー全体がダウンする可能性があります。
services:
web:
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
サーバーの総リソースを考慮し、すべてのコンテナのlimits合計が容量を超えないよう設定します。
ログローテーションの設定
デフォルトではログが無制限に蓄積されます。必ずログローテーションを設定しましょう。
services:
web:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
compress: "true"
この設定で、ログは最大30MB(10MB × 3ファイル)までに制限されます。
セキュリティ対策
機密情報の保護
パスワードやAPIキーをdocker-compose.ymlに直接書かないことが最重要です。必ず環境変数(${DB_PASSWORD})で参照し、実際の値は.envファイルに記述します。
# ❌ 悪い例
environment:
- POSTGRES_PASSWORD=my_secret_password
# ⭕ 良い例
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
ネットワークの分離とポート制限
コンテナ間通信は適切にネットワークを分離します。
services:
web:
networks:
- frontend
- backend
ports:
- "80:3000" # 外部公開
db:
networks:
- backend
expose:
- "5432" # コンテナ間のみ
networks:
frontend:
backend:
データベースはexposeを使い、コンテナ間通信のみ許可します。portsは外部に公開されるため、内部サービスには使いません。
サーバーレベルでもファイアウォールを設定します。
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw deny 5432/tcp # PostgreSQL
sudo ufw enable
イメージのバージョン管理
# ❌ 予期しない変更が入る可能性
image: node:latest
# ⭕ 具体的なバージョンを指定
image: node:18.17.1
バージョンを固定したら、定期的にセキュリティアップデートを確認し、計画的に更新します。脆弱性スキャンツール(Trivy、Docker Scanなど)を活用しましょう。
trivy image myapp:1.2.3
本番環境へのデプロイと運用
デプロイの基本手順
- イメージのビルドとプッシュ
docker build -t myapp:1.2.3 .
docker push myapp:1.2.3
- 本番環境での更新
# 最新イメージを取得
docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
# コンテナを再作成
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# 古いイメージを削除
docker image prune -f
ダウンタイムを最小化する更新
ブルーグリーンデプロイメントの簡易版を実現できます。
# 新バージョンを別名で起動
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --scale web=2
# ヘルスチェック確認後、古いコンテナを停止
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --scale web=1
バックアップとロールバック
定期的なバックアップスクリプトを作成します。
#!/bin/bash
# backup.sh
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR
# データベースバックアップ
docker-compose exec -T db pg_dump -U postgres myapp > $BACKUP_DIR/db.sql
# ボリュームバックアップ
docker run --rm -v db-data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/db-data.tar.gz -C /data .
ロールバック時は、イメージのバージョンを戻して再デプロイします。
# .envのAPP_VERSIONを前バージョンに変更
vi .env
# 再デプロイ
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
監視とトラブルシューティング
基本的な監視コマンド
# コンテナの状態確認
docker-compose ps
# リソース使用状況
docker stats
# ログ確認
docker-compose logs -f web
docker-compose logs --tail=100 db
よくあるトラブルと解決方法
コンテナが起動しない場合:
# 詳細ログを確認
docker-compose logs web
# ヘルスチェック状態を確認
docker inspect --format='{{json .State.Health}}' container_name
メモリ不足の場合:
リソース制限を見直し、不要なコンテナを停止します。
# メモリ使用量の多いコンテナを特定
docker stats --no-stream --format "table {{.Container}}\t{{.MemUsage}}"
ディスク容量不足の場合:
# 未使用リソースを削除
docker system prune -a --volumes
まとめ
Docker Composeは、適切な設定と運用を行えば本番環境でも十分に使えるツールです。特に中小規模のシステムでは、Kubernetesのような複雑なツールより、シンプルで管理しやすいDocker Composeが適しています。
重要なポイント:
- 開発環境と本番環境の設定を明確に分離する
- 自動再起動、リソース制限、ログローテーションを必ず設定する
- 機密情報は環境変数で管理し、Gitにコミットしない
- イメージのバージョンを固定し、定期的にアップデートする
- 定期的なバックアップとロールバック手順を準備する
月間数十万PV程度のWebサービスや、数十人が利用する社内システムなら、Docker Composeで十分に安定稼働できます。「完璧なシステム」よりも「現実的に運用できるシステム」を選ぶことが、中小企業には重要です。
まずは小さく始めて、システムの成長に合わせて段階的に改善していきましょう。不明点があれば、Docker公式ドキュメントやコミュニティフォーラムを活用してください。