
docker-compose.yml の書き方完全ガイド【Docker Compose v2対応・MySQL・Redis・Nginx設定サンプル付き】【2026年版】
Docker Composeを使い始めたとき「公式ドキュメントを読んだはずなのに、なぜか動かない」「バージョンが変わって書き方が違う」と感じた経験はないだろうか。
このガイドでは、Docker Compose v2への移行後の最新記法に対応した docker-compose.yml の書き方を、実際に動作するサンプルコード付きで解説する。MySQL・Redis・Nginxを組み合わせた本番同等の構成まで実際に手を動かして学べるよう構成した。
筆者は本番環境・開発環境ともにDocker Composeを日常的に使用しており、v1系からv2への移行で遭遇したトラブルも含めて実体験を交えて解説する。

Docker Compose v1 vs v2:何が変わったのか
2026年現在、docker-compose(ハイフンあり)コマンドはEnd of Life(EoL)を迎えており、docker compose(スペース区切り)が正式コマンドとなっている。
主な変更点を整理しておく。
| 項目 | v1(旧) | v2(現行) |
|---|---|---|
| コマンド | docker-compose up |
docker compose up |
| インストール | pip/単体バイナリ | Docker CLI プラグイン(同梱) |
version: フィールド |
必須("3.8" 等) |
不要(廃止推奨) |
depends_on の条件指定 |
非対応 | condition: service_healthy 対応 |
| プロファイル機能 | 非対応 | profiles: で環境分離可能 |
version: "3.8" のような記述はもはや必要ない。 Docker Composeのスキーマバージョン管理はEoLとなり、現在は単一スキーマに統一されている。既存のコードに書かれていても動作はするが、新規作成時は省略するのが推奨される。
# v2のバージョン確認
docker compose version
# Docker Compose version v2.24.0

前提条件
このガイドを進める前に、以下の環境が必要です。
- OS: macOS / Linux / Windows(WSL2推奨)
- Docker: Docker Desktop 4.x 以上 または Docker Engine 24.x 以上
- 前提知識: コマンドライン基本操作、Dockerの基本概念(コンテナ・イメージ)
# バージョン確認
docker --version
# Docker version 26.x.x
docker compose version
# Docker Compose version v2.24.x
Windowsユーザーへ: Docker DesktopとWSL2の組み合わせを推奨する。WSL2なしのHyper-V構成ではボリュームマウントが遅く、開発体験が著しく悪化する。
全体の流れ
このガイドは以下の5ステップで構成されています。
- 基本構文の理解 — 10分
- MySQL設定の実装 — 15分
- Redis設定の追加 — 10分
- Nginx設定の追加 — 15分
- 本番同等構成への仕上げ — 20分
ステップ1: docker-compose.ymlの基本構文
最小構成から始めて、徐々に複雑な設定を加えていく。まず単一のWebアプリコンテナを定義する例を見てみよう。
# docker-compose.yml(最小構成)
services:
app:
image: nginx:alpine
ports:
- "8080:80"
この6行だけで docker compose up を実行すると、ローカルの8080番ポートでNginxが起動する。
サービス定義の主要フィールド
各サービス(コンテナ)で使用頻度の高いフィールドをまとめた。
| フィールド | 用途 | 例 |
|---|---|---|
image |
使用するDockerイメージ | mysql:8.0 |
build |
Dockerfileからビルド | build: . |
ports |
ポートマッピング ホスト:コンテナ |
"3306:3306" |
volumes |
ボリュームマウント | ./data:/var/lib/mysql |
environment |
環境変数の設定 | MYSQL_ROOT_PASSWORD: secret |
depends_on |
起動順序の依存関係 | depends_on: - db |
networks |
接続するネットワーク | networks: - backend |
restart |
再起動ポリシー | restart: unless-stopped |
ビルドとイメージの使い分け
services:
# パターン1: 公式イメージをそのまま使う
db:
image: mysql:8.0
# パターン2: カレントディレクトリのDockerfileをビルド
app:
build: .
# パターン3: ビルドコンテキストとDockerfileを明示指定
worker:
build:
context: ./worker
dockerfile: Dockerfile.prod
args:
APP_ENV: production
✅ ステップ1完了の確認: docker compose config を実行してYAML構文エラーがないことを確認できれば完了。
ステップ2: MySQL設定の実装
MySQLコンテナの設定は「初回起動時の初期化処理」「文字コード設定」「データ永続化」の3点が重要だ。
MySQLコンテナの基本定義
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: myapp_development
MYSQL_USER: myapp
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./docker/mysql/conf.d:/etc/mysql/conf.d:ro
- ./docker/mysql/init:/docker-entrypoint-initdb.d:ro
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db_data:
MySQL設定ファイル(my.cnf)
./docker/mysql/conf.d/my.cnf として配置する。
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
explicit_defaults_for_timestamp = 1
default_authentication_plugin = mysql_native_password
# パフォーマンス調整(開発環境向け)
innodb_buffer_pool_size = 256M
max_connections = 100
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
注意: MySQL 8.0以降、デフォルトの認証方式が
caching_sha2_passwordに変更された。古いクライアントライブラリを使う場合はdefault_authentication_plugin = mysql_native_passwordを明示しないと接続エラーになる。ただしdefault_authentication_pluginは MySQL 8.4.0 で完全削除されており、mysql:8.4以降のイメージを使う場合は代わりにauthentication_policy = mysql_native_passwordを設定すること。
初期データの投入(init スクリプト)
./docker/mysql/init/01_create_db.sql として配置する。/docker-entrypoint-initdb.d/ ディレクトリに配置したファイルはコンテナの初回起動時のみ実行される。
-- 開発・テスト用データベースを作成
CREATE DATABASE IF NOT EXISTS myapp_development
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS myapp_test
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- アプリユーザーに権限付与
GRANT ALL PRIVILEGES ON myapp_development.* TO 'myapp'@'%';
GRANT ALL PRIVILEGES ON myapp_test.* TO 'myapp'@'%';
FLUSH PRIVILEGES;
環境変数は .env ファイルで管理する
パスワード等の機密情報はdocker-compose.yml内に直書きせず、.env ファイルで管理する。
# .env(.gitignoreに追加すること)
MYSQL_ROOT_PASSWORD=your_root_password_here
MYSQL_PASSWORD=your_app_password_here
Docker Composeは .env ファイルを自動で読み込むため、${MYSQL_ROOT_PASSWORD} のように参照できる。

✅ ステップ2完了の確認: docker compose up db を実行後、docker compose exec db mysql -u root -p でログインできれば完了。
ステップ3: Redisの設定
Redisはセッション管理・キャッシュ・ジョブキューで多用される。設定は比較的シンプルだが、データ永続化の要否を最初に決めておくことが重要だ。
Redis基本設定
services:
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
volumes:
- redis_data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
redis_data:
Redisの永続化オプション
| オプション | コマンド | 特徴 |
|---|---|---|
| 永続化なし | (デフォルト) | 再起動でデータ消失。キャッシュ用途に最適 |
| AOF(Append Only File) | --appendonly yes |
全書き込みをログ記録。信頼性高いが容量大 |
| RDB(スナップショット) | --save 900 1 |
定期スナップショット。バランス型 |
開発環境ではデータ消失してもよいなら volumes マウントを省略してもよい。本番相当の動作確認をしたい場合は AOF 永続化を推奨する。
アプリからの接続設定
# .env に追加
REDIS_PASSWORD=your_redis_password_here
REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
✅ ステップ3完了の確認: docker compose exec redis redis-cli -a ${REDIS_PASSWORD} ping で PONG が返れば完了。
ステップ4: Nginxをリバースプロキシとして設定
Nginxをリバースプロキシとして追加し、Webアプリへのリクエストを転送する構成を作る。
Nginxサービス定義
services:
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
- ./docker/nginx/ssl:/etc/nginx/ssl:ro
- nginx_logs:/var/log/nginx
depends_on:
app:
condition: service_healthy
networks:
- frontend
- backend
volumes:
nginx_logs:
Nginx設定ファイル(リバースプロキシ)
./docker/nginx/conf.d/default.conf として配置する。
upstream app_backend {
server app:3000;
# 複数インスタンスへの分散(スケールアウト時)
# server app_2:3000;
}
server {
listen 80;
server_name localhost;
# アクセスログ
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# ファイルアップロードサイズ上限
client_max_body_size 10M;
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
# WebSocket対応(必要な場合)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
# ヘッダー転送
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;
}
# 静的ファイルはNginxで直接配信
location /assets/ {
alias /var/www/app/public/assets/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}

✅ ステップ4完了の確認: curl http://localhost でアプリのレスポンスが返れば完了。
ステップ5: 本番同等構成への仕上げ
ここまでの設定を統合し、healthcheck と depends_on で起動順序を制御した完全版を組み上げる。
完成版 docker-compose.yml
# docker-compose.yml(全サービス統合版)
services:
# ==============================
# Webアプリケーション
# ==============================
app:
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
environment:
RAILS_ENV: development
DATABASE_URL: mysql2://myapp:${MYSQL_PASSWORD}@db/myapp_development
REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
volumes:
- .:/app
- bundle_cache:/usr/local/bundle
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- backend
# ==============================
# MySQL データベース
# ==============================
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: myapp_development
MYSQL_USER: myapp
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./docker/mysql/conf.d:/etc/mysql/conf.d:ro
- ./docker/mysql/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- backend
# ==============================
# Redis キャッシュ・セッション
# ==============================
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# ==============================
# Nginx リバースプロキシ
# ==============================
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
depends_on:
app:
condition: service_healthy
networks:
- frontend
- backend
# ==============================
# ネットワーク定義
# ==============================
networks:
frontend:
driver: bridge
backend:
driver: bridge
# ==============================
# ボリューム定義
# ==============================
volumes:
db_data:
redis_data:
bundle_cache:
.env ファイルのテンプレート
# .env.example(リポジトリに含める)
MYSQL_ROOT_PASSWORD=change_me_root
MYSQL_PASSWORD=change_me_app
REDIS_PASSWORD=change_me_redis
実際の .env ファイルは .gitignore に追加して、リポジトリに含めないこと。
よく使うdocker composeコマンド
# サービスをバックグラウンドで起動
docker compose up -d
# 特定のサービスのみ起動
docker compose up -d db redis
# ログをリアルタイム確認
docker compose logs -f app
# 特定サービスのシェルに入る
docker compose exec app bash
# コンテナ内でコマンド実行(使い捨てコンテナ)
docker compose run --rm app bundle exec rails db:migrate
# サービスを停止・削除
docker compose down
# ボリュームごと削除(データ初期化)
docker compose down -v
# 設定の構文チェック
docker compose config
v1コマンドからv2への対応表
# 旧コマンド → 新コマンド
docker-compose up → docker compose up
docker-compose down → docker compose down
docker-compose exec → docker compose exec
docker-compose run → docker compose run
docker-compose logs → docker compose logs
docker-compose ps → docker compose ps
docker-compose build → docker compose build
docker-compose pull → docker compose pull
トラブルシューティング
| 症状 | 原因 | 解決策 |
|---|---|---|
depends_on を設定したのにDB接続エラー |
depends_on はプロセス起動を待つだけ。DB準備完了は待たない |
healthcheck + condition: service_healthy を使う |
| MySQL初期化スクリプトが実行されない | db_data ボリュームにデータが残っている |
docker compose down -v でボリュームごと削除して再起動 |
version: "3.8" 警告が出る |
Docker Compose v2ではversionフィールドは廃止 | version: 行を削除する |
| Macでボリュームマウントが遅い | osxfsのパフォーマンス問題 | delegated オプション追加、またはDocker Desktop VirtioFS設定を有効化 |
Redis認証エラー WRONGPASS |
パスワードが一致していない | .env の REDIS_PASSWORD とコマンドの --requirepass を確認 |
| コンテナ間でホスト名解決できない | 同一ネットワークに属していない | 各サービスに同じ networks を設定する |
まとめ
このガイドでは、Docker Compose v2対応の docker-compose.yml の書き方を以下の順で解説した。
- v1とv2の違い:
docker-composeコマンドのEoL、version:フィールドの廃止、depends_onのhealthcheck条件対応 - MySQL設定: 文字コード設定、初期データ投入、named volumesによる永続化
- Redis設定: パスワード認証、AOF永続化、healthcheckの設定
- Nginx設定: リバースプロキシ設定、静的ファイル配信、ヘッダー転送
- 統合構成: healthcheck + depends_on による起動順序制御、ネットワーク分離
Docker Compose v2への移行を済ませておくことで、今後のDockerエコシステムのアップデートにも対応しやすくなる。次のステップとして、Docker buildxでマルチプラットフォームイメージをAWS ECRにプッシュする完全ガイドも参照してほしい。



