🎼 Docker Composeとは

Docker Composeは、複数のコンテナをまとめて管理するためのツールです。 設定をdocker-compose.ymlというファイルに書いておくことで、1コマンドで起動・停止ができます。

😰 Before(手動)

  • ・ネットワーク作成
  • ・MySQLコンテナ起動(長いコマンド)
  • ・Laravelコンテナ起動(長いコマンド)
  • ・nginxコンテナ起動(長いコマンド)
  • ・停止も3回、削除も3回...

😊 After(Compose)

  • ・起動: docker compose up -d
  • ・停止: docker compose down
  • ・設定はymlファイルに保存
  • ・チームで共有できる

📝 新旧コマンドの違い

ネット上には2種類のコマンドが混在しています。

docker compose(スペース) 新しい書き方(V2)。こちらを使う
docker-compose(ハイフン) 古い書き方(V1)。非推奨

📌 Docker Desktop をインストールしていれば docker compose(V2)が使えます。
古い記事では docker-compose と書かれていることがありますが、同じ機能です。

V2 でのその他の変更点
V1(旧) V2(新)
コマンド docker-compose docker compose
STATUS 表示 Up 10 minutes running
ps の出力 IMAGE 列あり SERVICE 列あり

📌 古い記事やチュートリアルで表示が違う場合は、バージョンの違いです。

📝 docker-compose.ymlを書いてみよう

前のセクションで手動起動した構成を、ymlファイルに書き換えましょう。

⚠️ YAMLはインデントがとても重要!

YAMLファイルはインデント(字下げ)で階層構造を表現します。
スペースの数が違うだけでエラーになるので、注意してください。

✅ 正しい例
services:
  app:
    image: php:8.4-fpm
    volumes:
      - ./src:/var/www/html
❌ 間違い例
services:
  app:
   image: php:8.4-fpm  ← 1個足りない
     volumes:  ← 1個多い
      - ./src:/var/www/html

📌 スペース2個で1階層を表します(タブ文字は使わない)

📖 YAMLの基本ルール

docker-compose.ymlはYAML(ヤムル)という形式で書きます。
JSONと似ていますが、インデント(字下げ)で階層を表現するのが特徴です。

JSONとの違い
JSON
{
  "services": {
    "db": {
      "image": "mysql:8.0"
    }
  }
}
YAML
services:
  db:
    image: mysql:8.0

📌 {}"" が不要でシンプル。インデントで階層を表現するので、誰が書いても同じ書き方になる

① キーと値(マッピング)

キー: 値 の形式で書きます。: の後にスペースが必要です。

image: mysql:8.0      # キー: 値
container_name: db    # キー: 値
② ネスト(階層構造)

インデント(スペース2個)で階層を表現します。

services:           # 第1階層
  db:               # 第2階層(スペース2個)
    image: mysql    # 第3階層(スペース4個)
    environment:    # 第3階層
      MYSQL_ROOT_PASSWORD: secret  # 第4階層(スペース6個)
③ 配列(リスト)

-(ハイフン + スペース)で配列の要素を表現します。

ports:
  - "8080:80"       # 配列の1つ目
  - "443:443"       # 配列の2つ目

volumes:
  - ./src:/var/www/html     # 配列の1つ目
  - ./docker:/etc/docker    # 配列の2つ目

depends_on:
  - db              # 配列の1つ目
  - redis           # 配列の2つ目
④ コメント

# 以降はコメントになります。メモを残せます。

# これはコメント
services:
  db:
    image: mysql:8.0  # 行末コメントもOK
⚠️ クォート("")が必要なケース

YAMLでは : が特別な意味を持つため、値に : が含まれる場合はクォートで囲みます。

ports:
  - "8080:80"    # ← : が含まれるのでクォート必要

image: mysql:8.0 # ← image: の後なので曖昧さがない、クォート不要
クォート 理由
8080:80 必要 : が含まれる
yes / no 必要 true/falseと誤解される
3.10 推奨 3.1と解釈されることも
📚 参考リンク

1docker-compose.ymlを作成

~/docker-laravel フォルダに以下の内容で作成してください。

cd ~/docker-laravel
# docker-compose.yml services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: laravel MYSQL_USER: laravel MYSQL_PASSWORD: secret volumes: - mysql-data:/var/lib/mysql - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf app: build: context: ./docker/php dockerfile: Dockerfile volumes: - ./src:/var/www/html environment: DB_CONNECTION: mysql DB_HOST: db DB_PORT: 3306 DB_DATABASE: laravel DB_USERNAME: laravel DB_PASSWORD: secret depends_on: - db web: image: nginx:1.28-alpine ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - app volumes: mysql-data:

📝 ymlファイルの構造

  • services: - コンテナの定義(db, app, web)
  • image: - 使用するイメージ
  • build: - Dockerfileからビルド(imageの代わり)
  • environment: - 環境変数(-e オプション相当)
  • volumes: - ボリュームマウント(-v オプション相当)
  • ports: - ポート公開(-p オプション相当)
  • depends_on: - 起動順序の制御

⚠️ 前のセクションで作成したファイルが必要

docker-compose.yml を使うには、以下のファイルが必要です:

  • docker/mysql/my.cnf - MySQL設定
  • docker/php/php.ini - PHP設定
  • docker/php/Dockerfile - PHPイメージ定義
  • docker/nginx/default.conf - nginx設定
  • src/ - Laravelプロジェクト

前のセクション「複数コンテナを手動で起動」で作成済みです。

🚀 起動してみよう

📍 docker compose コマンドの実行場所

docker compose 系のコマンドは全て docker-compose.yml があるフォルダで実行します。

cd ~/docker-laravel

📌 -f オプションで別の場所からも実行できます。
例: docker compose -f ~/docker-laravel/docker-compose.yml ps

2全コンテナを起動

docker compose up -d
[+] Running 4/4 ✔ Network docker-laravel_default Created ✔ Container docker-laravel-db-1 Started ✔ Container docker-laravel-app-1 Started ✔ Container docker-laravel-web-1 Started

たった1コマンドで3つのコンテナが起動しました!

3マイグレーションを実行

docker compose exec app php artisan migrate

「Yes」を入力してマイグレーションを実行してください。

4状態を確認

docker compose ps
NAME SERVICE STATUS PORTS docker-laravel-app-1 app Up 9000/tcp docker-laravel-db-1 db Up 3306/tcp docker-laravel-web-1 web Up 0.0.0.0:8080->80/tcp

🤔 docker container ls との違い

docker compose ps docker container ls
表示対象 このymlのコンテナだけ 全てのコンテナ
実行場所 docker-compose.ymlがある場所 どこでもOK

💡 複数のプロジェクトを動かしていても、関連するコンテナだけ見れるので便利!

📌 docker compose 系のコマンドは全て docker-compose.ymlがあるフォルダで実行します

5動作確認

ブラウザで http://localhost:8080 にアクセス!

Laravelのウェルカムページが表示されれば成功です!

🔍 docker-compose.ymlを分解して学ぼう

動きましたね!では、docker-compose.ymlの中身を一つずつ理解していきましょう。

📦 services: とは

起動するコンテナの一覧です。今回は3つのサービス(コンテナ)を定義しています。

🗄️
db
MySQL
🐘
app
PHP-FPM
🌐
web
nginx
services: db: # 1つ目のサービス ... app: # 2つ目のサービス ... web: # 3つ目のサービス ...

🤔 サービス名は --name と同じ?

似ていますが少し違います。

サービス名(db, app, web) --name
実際のコンテナ名 フォルダ名-サービス名-番号
例: docker-laravel-db-1
指定した名前そのまま
コンテナ間通信 サービス名でOK コンテナ名を使う

💡 コンテナ間の通信では dbapp などサービス名で接続できるので便利!
Docker Composeが自動でDNS解決してくれます。

🖼️ image: とは

使用するDockerイメージを指定します。
Docker Hubから自動でダウンロードされます。

db: image: mysql:8.0 # MySQLのバージョン8.0を使う web: image: nginx:1.28-alpine # nginx軽量版を使う

💡 手動起動での docker container run mysql:8.0 と同じです

🔧 environment: とは

環境変数を設定します。コンテナに渡す設定値です。

db: environment: MYSQL_ROOT_PASSWORD: secret # rootパスワード MYSQL_DATABASE: laravel # 作成するDB名 MYSQL_USER: laravel # 作成するユーザー MYSQL_PASSWORD: secret # そのパスワード

💡 手動起動での -e MYSQL_ROOT_PASSWORD=secret と同じです

📌 MySQLコンテナは起動時にこれらの環境変数を読んで、
「DBを作る」「ユーザーを作る」などの初期設定を自動で行います

⚠️ 本番環境では直接書かない!
パスワードがGitに残ってしまいます。本番では .env ファイルを使うのが一般的です。
開発環境なら直接書いてOKです。

📂 .env ファイルで環境変数を管理する(本番向け)

Docker Composeは、docker-compose.ymlと同じディレクトリにある.envファイルを自動的に読み込みます。

# .env ファイル DB_DATABASE=laravel DB_USERNAME=laravel DB_PASSWORD=secret
# docker-compose.yml の中で environment: DB_DATABASE: ${DB_DATABASE} # ← .envの値が展開される MYSQL_USER: ${DB_USERNAME} # ← .envの値が展開される

流れ:
1. docker compose up を実行
2. Docker Composeが同ディレクトリの.envを自動読み込み
3. ${変数名}の部分が.envの値に置き換わる
4. コンテナ内の環境変数として設定される

📌 注意: .envファイル自体がコンテナ内に入るわけではありません。
あくまでdocker-compose.ymlの変数展開に使われます。

📁 volumes: とは

ファイルの共有設定です。ホストPCのフォルダをコンテナ内で使えるようにします。

app: volumes: - ./src:/var/www/html # ホストのsrc → コンテナの/var/www/html db: volumes: - mysql-data:/var/lib/mysql # 名前付きボリューム(データ永続化)

💡 手動起動での -v ./src:/var/www/html と同じです

./src:/var/www/html
バインドマウント
ソースコードを共有
mysql-data:/var/lib/mysql
名前付きボリューム
DBデータを永続化
📦 名前付きボリュームの宣言って?

名前付きボリューム(mysql-data:など)を使う場合、
ファイルの末尾で宣言が必要です。

services: db: volumes: - mysql-data:/var/lib/mysql # ← 使う場所 volumes: # ← ファイル末尾で宣言 mysql-data: # ← ボリューム名を書くだけ

📌 宣言がないとエラーになります。バインドマウント(./src:など)は宣言不要です。

💾 どこに保存される?

Dockerが管理する専用の場所に保存されます。
(Mac/Windowsでは Docker Desktop 内、Linux では /var/lib/docker/volumes/

🔍 確認方法

docker volume ls
DRIVER VOLUME NAME local docker-laravel_mysql-data

🗑️ 削除方法

# Docker Compose で削除(コンテナと一緒に)
docker compose down -v
# 個別に削除
docker volume rm ボリューム名

⚠️ 削除するとDBのデータも消えます!

🚪 ports: とは

ポートの公開設定です。外部からコンテナにアクセスできるようにします。

web: ports: - "8080:80" # ホストの8080 → コンテナの80

💡 手動起動での -p 8080:80 と同じです

ブラウザ
localhost:8080
nginx
:80
🤔 DBはポート公開しないの?

DBは外部に公開しないのが一般的です(セキュリティ上の理由)。
コンテナ間(Docker ネットワーク内)でのみ通信できれば十分です。

web: ports: - "8080:80" # ← 外部からアクセスさせたい db: # ports なし ← 外部には公開しない

🖥️ 開発時にクライアントツールで接続したい場合

TablePlus、MySQL Workbench などで接続したい場合は、ポートを公開します。

ポート公開 ports: "3306:3306" クライアントツールで接続
exec docker compose exec db mysql ターミナルで接続

📁 開発と本番で設定を分ける方法

docker-compose.override.yml を使うのが一般的です。

docker-laravel/
├── docker-compose.yml # ベース設定
└── docker-compose.override.yml # 開発用(自動で読み込まれる)
# docker-compose.override.yml(開発用) services: db: ports: - "3306:3306" # ← 開発時だけ追加

📌 docker compose up自動的に両方がマージされます。
本番では override.yml を置かない or .gitignore に入れておけばOKです。

🔨 build: とは

Dockerfileからイメージをビルドします。
image: の代わりに使います。

app: build: context: . # ビルドする場所(カレントディレクトリ) dockerfile: docker/php/Dockerfile # Dockerfileのパス
image: 既存のイメージをそのまま使う
build: Dockerfileでカスタマイズしたイメージを作る

⏱️ depends_on: とは

起動順序を指定します。「このコンテナが先に起動してから、自分を起動して」という設定です。

app: depends_on: - db # dbが起動してからappを起動 web: depends_on: - app # appが起動してからwebを起動
① db
② app
③ web

⚠️ depends_onはコンテナの起動順序を制御するだけです。
「MySQLが接続可能になるまで待つ」わけではありません。

🤔 depends_on がなくても動く?

はい、動きます。

depends_on なし depends_on あり
起動順序 同時に起動(順番は運次第) 指定した順番で起動
通常の開発 だいたい動く だいたい動く

📌 なぜ「だいたい動く」? → コマンドを打ってからブラウザを開くまでに数秒かかりますよね。
その間にDBも起動完了しているので、アクセス時には問題なく動くことが多いです。

🌐 ネットワークとコンテナ名は?

docker-compose.ymlには --network--name を書いていません。
Docker Composeが自動で作成してくれます!

📡 ネットワーク名
フォルダ名_default 例: docker-laravel_default
docker network ls
📦 コンテナ名
フォルダ名-サービス名-番号
docker-laravel-db-1 docker-laravel-app-1 docker-laravel-web-1

💡 コンテナ間の通信はサービス名でOK!
appコンテナからDBに接続するとき、ホスト名は db と書くだけ

🔄 restart: とは(今回のサンプルには未使用)

コンテナが落ちたときに自動で再起動するかの設定です。
開発環境では不要ですが、本番環境では設定するのが一般的です。

db: image: mysql:8.0 restart: unless-stopped app: build: ./docker/php restart: unless-stopped web: image: nginx:alpine restart: unless-stopped
動作
no 再起動しない(デフォルト)
always 常に再起動
unless-stopped 手動停止以外は再起動 ← おすすめ
on-failure エラー終了時のみ再起動

💡 手動起動での --restart unless-stopped と同じです

🔄 docker container run との対応表

💡 docker-compose.yml は、docker container run のオプションを
YAML形式で書いているだけ!

難しく考えなくてOK。手動起動で使ったオプションをファイルに書いてるだけです。

手動起動(run) docker-compose.yml
--name db services:
db:
mysql:8.0 image: mysql:8.0
-e MYSQL_PASSWORD=secret environment:
MYSQL_PASSWORD: secret
-v ./src:/var/www/html volumes:
- ./src:/var/www/html
-p 8080:80 ports:
- "8080:80"
--network my-laravel-nw (自動で作成される!)
--restart unless-stopped restart: unless-stopped
※今回のサンプルでは未使用(本番向け)

💡 Docker Composeの便利なところ

  • ネットワークは自動作成 - docker network create は不要!
  • コンテナ名で通信できる - app から db に接続するとき、ホスト名は db でOK
  • 1コマンドで全部起動 - docker compose up -d だけ!

🛠️ よく使うdocker composeコマンド

💡 コマンド一覧を見るには

docker compose --help

使えるコマンド一覧が表示されます。困ったときはまずこれ!

コマンド 説明
docker compose up -d 全サービスをバックグラウンドで起動
docker compose down 全サービスを停止・削除
docker compose ps サービスの状態を表示
docker compose logs ログを表示
docker compose exec app bash コンテナ内でコマンド実行
docker compose restart 全サービスを再起動

それぞれ詳しく見ていきましょう。

📦 docker compose up - 起動

docker compose up -d

docker-compose.ymlに定義されたすべてのサービス(コンテナ)を起動します。

-d バックグラウンドで起動(detached mode)。これを付けないとターミナルがログで埋まります
--build 起動前にイメージを再ビルド。Dockerfileを変更した後に必要
web サービス名を指定すると、そのサービスだけ起動
# Dockerfileを変更した後
docker compose up -d --build
# appサービスだけ起動
docker compose up -d app

🧹 docker compose down - 停止・削除

docker compose down

すべてのコンテナを停止し、コンテナとネットワークを削除します。

down コンテナとネットワークを削除(ボリュームは残る)
down -v ボリュームも削除(DBデータも消える!)
down --rmi all イメージも削除(完全クリーン)

⚠️ -v を付けるとDBのデータも消えるので注意!

📋 docker compose ps - 状態確認

docker compose ps
NAME SERVICE STATUS PORTS docker-laravel-app-1 app running 9000/tcp docker-laravel-db-1 db running 3306/tcp docker-laravel-web-1 web running 0.0.0.0:8080->80/tcp

docker-compose.ymlで定義されたサービスの状態を表示します。

📊 STATUS の種類

running 実行中(正常)
exited 停止した(エラーか正常終了)
restarting 再起動中
created 作成済みだが起動していない

📌 全部 running になっていれば正常です。exited があればログを確認しましょう。

💡 docker compose ps は running も exited も表示

docker compose up で起動したコンテナは、running も exited も表示されます。
docker container ls と違って -a は不要)

📌 -adocker compose run で作成した一時コンテナも含めて表示するオプションです。

🔄 コマンドで STATUS が変わる

docker compose コマンドでコンテナの状態が変化します。

(なし)
up
running
stop
exited
start
running
down
(削除)
# 試してみよう
docker compose ps # running を確認
docker compose stop
docker compose ps # exited に変わる
docker compose start
docker compose ps # running に戻る

🤔 docker container ls との違い

docker compose ps docker container ls
表示対象 このymlのコンテナだけ 全てのコンテナ
実行場所 docker-compose.ymlがある場所 どこでもOK

💡 複数のプロジェクトを動かしていても、関連するコンテナだけ見れるので便利!

📌 docker compose 系のコマンドは全て docker-compose.yml があるフォルダで実行します。

📜 docker compose logs - ログ確認

docker compose logs

全サービスのログを表示します。エラーが起きたときに便利!

logs 全サービスのログを表示
logs app appサービスのログだけ表示
logs -f リアルタイムでログを追跡(Ctrl+Cで終了)
logs --tail 100 最新100行だけ表示
# appサービスのログをリアルタイムで追跡
docker compose logs -f app

🤔 何が出るの?

各コンテナの標準出力(stdout)標準エラー出力(stderr)が表示されます。
※ 各ソフトウェアが stdout に出力する内容が表示されます

db MySQL の起動ログ、エラーログ
app PHP-FPM のログ、アクセスログ
web nginx の起動ログ、アクセスログ

📌 ブラウザでアクセスすると GET /tasks のようなログがリアルタイムで流れます。

⚠️ ファイルに書かれるログ(Laravel の storage/logs/ など)はここには出ません。
docker compose exec app cat storage/logs/laravel.log で確認

💡 -d を付けないとログが出っぱなし

docker compose up(-d なし)で起動すると、ログが流れ続けます。

コマンド 動作 Ctrl+C
docker compose up フォアグラウンド + ログ表示 コンテナ停止
docker compose up -d
+ logs -f
バックグラウンド + ログ表示 ログだけ終了
(コンテナは動く)

📌 通常は -d を付けてバックグラウンドで起動します。

🖥️ docker compose exec - コンテナに入る

docker compose exec app bash
root@a1b2c3d4e5f6:/var/www/html#

起動中のコンテナの中に入ってコマンドを実行できます。

# appコンテナでphp artisanを実行
docker compose exec app php artisan migrate
# dbコンテナでMySQLに接続
docker compose exec db mysql -u root -p

📌 exit で抜けてもコンテナは停止しません。

💡 -it は不要

docker container exec では -it が必要でしたが、
docker compose exec自動で対話モードになります。

docker container exec -it コンテナ名 bash -it 必要
docker compose exec app bash -it 不要(自動)

🔄 docker compose restart - 再起動

docker compose restart

全サービスを再起動します(stop + start)。

# 特定のサービスだけ再起動
docker compose restart app

📌 設定ファイル(nginx.confなど)を変更した場合は再起動が必要です。

💡 stop / start / down の違い

docker compose stop 停止(コンテナは残る)
docker compose start 停止中のコンテナを起動
docker compose down 停止 + 削除(コンテナがなくなる)

📌 down でコンテナは削除され、次回 up で新しく作成されます。

🧹 停止と後片付け

6全コンテナを停止・削除

docker compose down
[+] Running 4/4 ✔ Container docker-laravel-web-1 Removed ✔ Container docker-laravel-app-1 Removed ✔ Container docker-laravel-db-1 Removed ✔ Network docker-laravel_default Removed

1コマンドで全部片付きました!

📝 オプション

docker compose down コンテナとネットワークを削除(ボリュームは残る)
docker compose down -v ボリュームも削除(DBデータも消える)
docker compose down --rmi all イメージも削除

📝 このセクションのまとめ

🎉 Docker Composeで解決!

問題 手動 Compose
コマンドの長さ 何行も打つ 1コマンド
設定の保存 残らない ymlに保存
起動順序 手動で管理 depends_onで自動
チーム共有 難しい ymlをGitで共有
ネットワーク 手動作成 自動作成

✅ 学んだこと

  • docker-compose.ymlの書き方
  • runオプションとymlの対応関係
  • docker compose up / down / ps / logs
  • depends_on で起動順序を制御
  • build でDockerfileからビルド

🎯 Dockerの本質を実践できました

講座の最初に「環境をコードで管理する」がDockerの本質だとお伝えしました。

Docker Composeを学んだことで、まさにそれを実践できるようになりました:

  • docker-compose.yml → 環境構成をコードで定義
  • Dockerfile → コンテナの中身をコードで定義
  • Gitで管理 → チーム全員が同じ環境を再現

🎉 これで「環境をコードで管理する」を実践できるエンジニアになりました!