そう感じているなら、Docker Composeを使うタイミングが来ています。
Docker Composeは複数のコンテナをyamlファイル1本で定義・管理できるツールです。
この記事では、docker-compose.ymlの書き方からWordPressとMySQLコンテナの連携・起動まで、実際のサーバー出力例を交えてハンズオン形式で解説します。
さらに、
profiles 機能を使った開発・本番サービスの切り替え、Docker Compose v2.22で正式搭載された docker compose watch を使ったホットリロード開発環境の構築、--scale と deploy.replicas によるスケールアウト、そして docker compose run を使ったDBマイグレーションやテスト実行まで、一歩踏み込んだ実践内容もカバーします。なお、Docker Composeを使う前提としてDockerが動いていることが必要です。Linuxへのインストール手順は後述しますが、WindowsのWSL2上で試したい場合は別記事も参照してください。
動作確認環境: Rocky Linux 9.4 / Ubuntu 24.04 LTS(Docker Engine 26.x・Docker Compose Plugin v2.27)
この記事のポイント
・docker compose up -d 1コマンドでWordPress+MySQLを同時起動できる
・docker-compose.ymlでサービス間の依存・ネットワーク・ボリュームを一元管理する
・コンテナが起動しない時はdocker compose logsで原因を即座に特定できる
・docker compose runでDBマイグレーション・テストを一時コンテナで実行できる
・--scale や deploy.replicas でコンテナを複数台に増やして負荷分散の基礎を体験できる
・profilesでサービスに開発・本番のプロファイルを割り当て、docker compose --profile dev up で環境ごとに起動するコンテナを1ファイルで管理できる
・docker compose watchのsync・rebuild・sync+restartを使い分けてファイル変更を自動反映できる
・docker compose down でコンテナ・ネットワークをまとめてクリーンアップできる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Docker Composeとは?複数コンテナを一括管理する仕組み
まず、Dockerそのものを簡単に整理しておきます。Dockerはアプリケーションと、その動作に必要なファイル・設定を「コンテナ」という軽量な仮想環境にまとめて動かすツールです。
仮想マシン(VirtualBox等)と比べると、OSをまるごと持たないぶん起動が速くディスク消費も少ないのが特徴です。
| 比較項目 | コンテナ(Docker) | 仮想マシン(VirtualBox等) |
|---|---|---|
| 起動時間 | 数秒 | 数十秒~数分 |
| ディスク容量 | 数MB~数百MB | 数GB |
| OSカーネル | ホストOSのカーネルを共有 | OSを丸ごと持つ |
| 主な用途 | アプリ開発・動作確認・本番デプロイ | OS丸ごと検証・デスクトップ環境 |
docker runでそれぞれ起動することもできますが、毎回長いオプションを打つのは現実的ではありません。
Docker Composeはその問題を解決するツールです。
docker-compose.yml(またはcompose.yml)というyamlファイルに「どのコンテナを、どのネットワークで、どのボリュームにマウントして起動するか」をすべて記述します。
あとは docker compose up の1コマンドで全コンテナが一斉に起動します。
さらに
--scale オプションを使えば、WordPressコンテナを複数台並べるスケールアウトも1コマンドで行えます。Docker Composeが解決する3つの課題
・長い起動コマンドの繰り返し:yamlに一度書けば、以降は docker compose up だけで済む・コンテナ間のネットワーク設定:Composeが自動で専用ネットワークを作成し、サービス名でIPなしに通信できる
・ボリューム管理:データ永続化のボリュームをyamlで宣言し、docker compose down してもデータが残る
Docker Compose v1とv2の違い
古い情報では docker-compose(ハイフンあり)と書いているものがあります。現在の主流はDocker Engine同梱の Docker Compose Plugin(v2) で、コマンドは
docker compose(スペース区切り)です。本記事はv2を前提にしています。
# v2の確認方法 $ docker compose version Docker Compose version v2.27.1
事前準備|Docker ComposeをLinuxにインストールする
Rocky Linux 9やUbuntu 24.04では、Docker Engine導入時にComposeプラグインが同梱されています。以下の手順でDocker Engineを入れれば、docker composeコマンドがそのまま使えます。
1. Rocky Linux 9にDockerをインストールする
# Docker公式リポジトリを追加 $ sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo # Docker Engine・Compose Pluginを一括インストール $ sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # サービスを起動・自動起動設定 $ sudo systemctl enable --now docker # 動作確認 $ docker compose version Docker Compose version v2.27.1
2. Ubuntu 24.04にDockerをインストールする
# 依存パッケージを追加 $ sudo apt-get install -y ca-certificates curl # Docker GPGキーを追加 $ sudo install -m 0755 -d /etc/apt/keyrings $ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc # リポジトリを追加してapt updateを実行 $ sudo apt-get update && sudo apt-get install -y \ docker-ce docker-ce-cli containerd.io docker-compose-plugin # 動作確認 $ docker compose version Docker Compose version v2.27.1
3. 一般ユーザーでdockerを実行できるようにする
sudoなしでdockerコマンドを使うには、自分のユーザーをdockerグループに追加します。# dockerグループへの追加(user_nameを自分のユーザー名に変更) $ sudo usermod -aG docker user_name # 設定反映(再ログインまたはnewgrp) $ newgrp docker # 確認 $ docker info | grep -i server Server Version: 26.1.4
4. Dockerデーモンの起動確認
docker composeを実行する前に、Dockerデーモンが起動していることを確認しましょう。「Cannot connect to the Docker daemon」エラーが出る場合は、デーモンが停止しています。
# Dockerデーモンの状態を確認する $ sudo systemctl status docker # 停止していれば起動する $ sudo systemctl start docker
docker-compose.ymlを作成する|WordPress+MySQLの設定
作業用ディレクトリを作成し、docker-compose.ymlを配置します。このファイル1本がWordPressとMySQLの構成をすべて定義します。
1. 作業ディレクトリを作成する
$ mkdir ~/wordpress-compose && cd ~/wordpress-compose
2. docker-compose.ymlを作成する
以下の内容でdocker-compose.ymlを作成してください。services: db: image: mysql:8.0 restart: always environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: wordpress MYSQL_USER: wpuser MYSQL_PASSWORD: wppassword volumes: - db_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpassword"] interval: 10s timeout: 5s retries: 5 wordpress: image: wordpress:6.5-php8.3-apache restart: always depends_on: db: condition: service_healthy ports: - "8080:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wpuser WORDPRESS_DB_PASSWORD: wppassword WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html volumes: db_data: wp_data:
・services.db:MySQLコンテナの定義。MySQL 8.0イメージを使用する
・services.wordpress:WordPressコンテナの定義。PHP 8.3+Apacheのイメージを使用する
・healthcheck:MySQLの初期化が完了したかどうかをmysqladmin pingで定期的に確認する設定。これがあることでWordPressは「MySQLが本当に準備できた状態」を待って起動する
・depends_on: condition: service_healthy:dbサービスのhealthcheckが「healthy」になってからwordpressを起動する。単純な depends_on: - db より確実
・WORDPRESS_DB_HOST: db:3306:Composeが自動作成した内部ネットワーク上でサービス名「db」で通信できる
・ports: "8080:80":ホストの8080番ポートをコンテナの80番にマッピングする
・volumes(末尾):db_dataとwp_dataという名前付きボリュームを宣言。コンテナを停止してもデータは保持される
3. .envファイルでパスワードを分離する(推奨)
パスワードをyamlに直書きするのは開発環境では構いませんが、Gitで管理する場合は .env ファイルに分離することを推奨します。.envファイルを作成してから .gitignore に追加し、Gitにパスワードが混入しないようにしましょう。
# .envファイルを作成 $ cat > .env << 'EOF' MYSQL_ROOT_PASSWORD=rootpassword MYSQL_DATABASE=wordpress MYSQL_USER=wpuser MYSQL_PASSWORD=wppassword EOF # .gitignoreに追加してGitに含めない(本番パスワードの流出防止) $ echo ".env" > .gitignore
# docker-compose.yml の db セクション(抜粋) db: environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} # wordpress セクション(抜粋) wordpress: environment: WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
コンテナを起動してWordPressにアクセスする
1. docker compose upでコンテナを起動する
docker-compose.ymlがあるディレクトリで以下を実行します。# バックグラウンドで起動(-d = detachedモード) $ docker compose up -d # 実際の出力例 [+] Running 4/4 ✔ Network wordpress-compose_default Created 0.1s ✔ Volume "wordpress-compose_db_data" Created 0.0s ✔ Volume "wordpress-compose_wp_data" Created 0.0s ✔ Container wordpress-compose-db-1 Started 0.4s ✔ Container wordpress-compose-wp-1 Started 0.8s
Composeが自動でネットワーク(wordpress-compose_default)と2つのボリュームを作成し、dbコンテナが先に起動してからwordpressコンテナが起動しています。
2. コンテナの状態を確認する
$ docker compose ps NAME IMAGE STATUS PORTS wordpress-compose-db-1 mysql:8.0 Up 3306/tcp, 33060/tcp wordpress-compose-wp-1 wordpress:6.5-php8.3-apache Up 0.0.0.0:8080->80/tcp
healthcheckを設定している場合、Statusには「Up (healthy)」と表示されます。
「Up (health: starting)」は初期化中のため、「healthy」になるまで数十秒待ってください。
3. WordPressの初期設定を行う
ブラウザで http://localhost:8080 にアクセスします。WordPressの「ようこそ」画面が表示されたら成功です。
言語選択 → サイト名・管理者アカウント設定 → 「WordPressをインストール」で完了します。
リモートの検証サーバーで動かしている場合は、localhostをサーバーのIPアドレスに置き換えてアクセスしてください(例: http://192.168.1.100:8080)。
よく使うDocker Composeコマンド一覧
| やりたいこと | コマンド |
|---|---|
| コンテナをバックグラウンドで起動 | docker compose up -d |
| コンテナの状態確認 | docker compose ps |
| ログをリアルタイム表示 | docker compose logs -f |
| 特定サービスのログを表示 | docker compose logs -f wordpress |
| コンテナを停止(削除しない) | docker compose stop |
| 停止したコンテナを再起動 | docker compose start |
| コンテナを停止して削除 | docker compose down |
| コンテナ・ボリュームも含めて完全削除 | docker compose down -v |
| yamlを変更後にコンテナを再作成 | docker compose up -d --force-recreate |
| 起動中コンテナでシェルを実行 | docker compose exec wordpress bash |
| 一時コンテナでコマンドを実行(完了後に自動削除) | docker compose run --rm サービス名 コマンド |
| CIやスクリプトから非対話モードで実行 | docker compose run --rm -T サービス名 コマンド |
| 設定ファイルの構文チェック | docker compose config |
| イメージの再ビルドを含めて起動 | docker compose up -d --build |
| wordpressを3台に増やして起動 | docker compose up --scale wordpress=3 -d |
| 開発専用サービスを含めてprofileを指定して起動 | docker compose --profile dev up -d |
| ファイル変更を監視してコンテナへ自動同期 | docker compose watch |
| 起動とwatch開始を同時に行う | docker compose up --watch |
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Docker ComposeをはじめとするDockerの実践スキルを体系的に学べる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
docker compose runで一時タスクを実行する|execとの使い分け
Composeでサービスを運用していると、「DBマイグレーションをデプロイ前に実行したい」「CIでテストを走らせてPass/Failを判定したい」「本番コンテナに影響を与えずデバッグシェルを開きたい」といった場面が頻繁に発生します。こういった「ワンショットの処理」に最適なのが
docker compose run です。docker compose exec との違いを押さえておきましょう。exec はすでに起動しているコンテナにコマンドを送るのに対し、run は起動中のコンテナがなくても新しい一時コンテナを立ち上げてコマンドを実行します。サービス定義の環境変数・ネットワーク・ボリュームはそのまま引き継がれるため、本番と同じ設定で一時的な処理を安全に実行できます。| 比較項目 | docker compose run | docker compose exec |
|---|---|---|
| 前提条件 | コンテナが起動していなくてもよい | コンテナが起動済みである必要がある |
| コンテナの扱い | 新しいコンテナを作成して実行 | 既存の起動中コンテナに入る |
| 実行後のコンテナ | 停止(--rmで自動削除可) | 起動中コンテナはそのまま維持される |
| 終了コードの返し方 | コマンドの終了コードをそのまま返す | コマンドの終了コードをそのまま返す |
| 主な用途 | マイグレーション・テスト・初期化タスク | 起動中コンテナのデバッグ・ログ確認 |
1. --rmで終了後にコンテナを自動削除する(推奨)
デフォルトでは--rm が付かないため、実行済みコンテナがディスクに残り続けます。積み重なるとディスクを圧迫するため、ほとんどの場面では --rm を付けることを推奨します。# 実行後にコンテナを自動削除する(推奨パターン) $ docker compose run --rm web python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK # --rmなしで実行するとコンテナが停止状態で残り続ける(NG) $ docker ps -a CONTAINER ID IMAGE COMMAND STATUS NAMES d4a9e7f1c3b8 app-web "python manage.py" Exited (0) 7 seconds ago app-web-run-1
2. -TオプションでCIやスクリプトから呼び出す
docker compose run はデフォルトでTTYを割り当てます。CIサーバーやシェルスクリプトからの呼び出しではTTYがないため、-T(--no-TTY)を付けて非対話モードで実行します。-T なしでパイプに渡すと「input device is not a TTY」エラーが発生することがあります。# CIやシェルスクリプトから呼び出す場合(-Tを付ける) $ docker compose run --rm -T web pytest tests/ | tee test-results.txt # Laravelのマイグレーションをデプロイスクリプトに組み込む例 $ docker compose run --rm -T app php artisan migrate --force
3. DBマイグレーション・テスト実行の実践パターン
Djangoを例に、デプロイフローへの組み込み方を示します。docker compose run はコマンドの終了コードをそのまま返すため、CI/CDパイプラインのPass/Fail判定に直接使えます。# DjangoのDBマイグレーション(Ubuntu 24.04 LTS + Docker Compose v2.27 での実測) $ docker compose run --rm -T web python manage.py migrate [+] Running 1/1 ✔ Container myapp-db-1 Healthy Operations to perform: Apply all migrations: admin, auth, contenttypes, myapp, sessions Running migrations: Applying myapp.0001_initial... OK Applying myapp.0002_add_user_profile... OK # テスト実行(終了コード1=失敗をCIがそのまま受け取れる) $ docker compose run --rm -T web pytest tests/ -v ... 4 failed, 43 passed in 12.38s $ echo $? 1
depends_on に condition: service_healthy を設定しておくと、docker compose run もDBのhealthcheckが通過するまで待機してからコマンドを実行します。本記事で作成したdocker-compose.ymlはhealthcheckを設定済みのため、この問題は発生しません。4. 本番稼働中のコンテナに影響を与えずデバッグシェルを開く
稼働中のサービスに影響を与えずに、同じ設定で新しいシェルを開きたい場合にもrun が便利です。exec で本番コンテナに入って操作すると誤操作が即本番に影響するリスクがありますが、run なら独立した一時コンテナで調査できます。# 稼働中のwebコンテナには影響を与えずに新しいシェルを開く $ docker compose run --rm web bash root@7f3c4a1b2d9e:/app# python manage.py shell Python 3.12.3 >>> from myapp.models import User >>> User.objects.count() 1523 >>> exit() root@7f3c4a1b2d9e:/app# exit # --rmでコンテナは自動削除される
複数コンテナに増やす|--scaleとdeploy.replicasの使い方
WordPress環境が安定して動いたら、次のステップとして「コンテナを複数台並べる」スケールアウトを試してみましょう。アクセスが増えてレスポンスが遅くなってきたとき、サーバーのCPU・メモリを増強するスケールアップと違い、コンテナを追加・削除するだけで処理能力を柔軟に調整できるのがスケールアウトの利点です。
注意点として、MySQLのような「状態を持つ」DBコンテナをむやみにスケールするとデータ競合が起きます。スケールアウトが効果的なのは、WordPressのような「ステートレス」なアプリコンテナです。
1. --scaleで台数を動的に変える
--scale はコマンドラインからサービスの起動数を動的に指定するオプションです。Composeファイルを変更せずに台数を変えられます。# wordpressサービスを3台で起動する $ docker compose up --scale wordpress=3 -d # 実行中のコンテナを確認する(ポートを "80" に変更済みの場合) $ docker compose ps NAME SERVICE STATUS PORTS wordpress-compose-db-1 db Up (healthy) 3306/tcp wordpress-compose-wordpress-1 wordpress Up 0.0.0.0:49153->80/tcp wordpress-compose-wordpress-2 wordpress Up 0.0.0.0:49154->80/tcp wordpress-compose-wordpress-3 wordpress Up 0.0.0.0:49155->80/tcp
ports: "8080:80" とホストポートを固定しているため、このままスケールすると2台目のコンテナがポートを確保できずエラーになります。WordPressをスケールするには、コンテナポートのみ公開する設計に変更し、nginxなどのリバースプロキシ経由でアクセスを一本化する構成が必要です。
# NG:ホストポートを固定するとスケール不可(2台目でエラー) ports: - "8080:80" # OK:コンテナポートのみ公開(ホスト側はDockerがランダムに割り当てる) ports: - "80"
# 3台から1台に縮小する(wordpress-2・wordpress-3が自動削除) $ docker compose up --scale wordpress=1 -d
2. deploy.replicasでComposeファイルに台数を定義する
deploy.replicas はComposeファイルに台数を静的に定義する方法です。docker compose up 時に --scale を指定しなくても、定義した台数が起動します。チームで台数をgitで管理したい場合に適しています。# docker-compose.yml(wordpressサービスの抜粋) wordpress: image: wordpress:6.5-php8.3-apache deploy: replicas: 3 # --scale指定なしでも3台起動する
# --scale不要。定義通り3台が起動する $ docker compose up -d [+] Running 4/4 ✔ Container wordpress-compose-db-1 Started ✔ Container wordpress-compose-wordpress-1 Started ✔ Container wordpress-compose-wordpress-2 Started ✔ Container wordpress-compose-wordpress-3 Started
| 比較項目 | --scale(コマンド指定) | deploy.replicas(Compose定義) |
|---|---|---|
| 台数の管理場所 | コマンドライン(その場限り) | docker-compose.yml(コード化) |
| 適切な用途 | 一時的な増減・負荷テスト | 台数を固定して運用したい場合 |
| git管理との相性 | 定義が残らない(手動作業) | Composeファイルとして履歴管理できる |
| CI/CDとの相性 | パラメータとして渡す必要がある | ファイルに定義があるのでそのままapply可 |
環境を切り替える|profilesで開発・本番サービスを分離する
WordPressの開発中、phpMyAdminをブラウザで操作しながらDB確認したい——でも本番サーバーにphpMyAdminを公開するのはセキュリティリスクです。こういった「開発時だけ起動したいサービス」を1つのdocker-compose.ymlで管理するのが
profiles 機能です。サービスに「dev」「prod」などのプロファイル名を割り当て、docker compose --profile dev up と指定するだけで、環境ごとに起動するコンテナを切り替えられます。profiles機能を使わない場合、開発環境用・本番環境用でcompose.ymlを別ファイルに分けるか、コメントアウトで管理するパターンが多く見られます。どちらも共通設定の二重管理や「本番で誤って開発ツールを起動する」ミスの温床になります。profilesを使えば1ファイルに統一したまま、コマンド引数か.envの変数1行で制御できます。
1. サービスにprofilesを割り当てる
サービス定義にprofiles: キーを追加します。重要な仕様:
profiles: を指定しないサービス(WordPressとMySQL)はプロファイルに関係なく常時起動します。profiles: を持つサービスは、対応するプロファイルを指定した場合のみ起動対象になります。逆に、全サービスにprofilesを付けてしまうと、--profile なしでは何も起動しない構成になるので注意してください。# docker-compose.yml(WordPress環境にprofiles設定を追加) services: db: image: mysql:8.0 restart: always environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} volumes: - db_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"] interval: 10s timeout: 5s retries: 5 wordpress: image: wordpress:6.5-php8.3-apache restart: always depends_on: db: condition: service_healthy ports: - "8080:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_DB_NAME: ${MYSQL_DATABASE} volumes: - wp_data:/var/www/html # 開発専用:phpMyAdmin(本番には絶対に公開しない) phpmyadmin: image: phpmyadmin:latest profiles: - dev ports: - "8081:80" environment: PMA_HOST: db depends_on: - db volumes: db_data: wp_data:
2. --profileオプションで起動する
--profile フラグは docker compose コマンド本体(サブコマンドの前)に付けます。# 開発環境(WordPress・MySQL・phpMyAdminを起動) $ docker compose --profile dev up -d [+] Running 4/4 ✔ Network wordpress-compose_default Created ✔ Container wordpress-compose-db-1 Started ✔ Container wordpress-compose-wp-1 Started ✔ Container wordpress-compose-phpmyadmin-1 Started # 本番相当(WordPress・MySQLのみ起動。phpMyAdminは除外) $ docker compose up -d [+] Running 3/3 ✔ Container wordpress-compose-db-1 Started ✔ Container wordpress-compose-wp-1 Started
--profile を指定しない通常の docker compose up -d ではphpMyAdminは起動しません。誤って本番サーバーで開発ツールが起動するリスクを構造的に排除できます。phpMyAdminが不要になったら
docker compose --profile dev down で停止・削除します。--profile なしの docker compose down は、profilesサービスを除いたコンテナのみを対象にするため、phpMyAdminコンテナが残ることがあります。3. .envファイルでプロファイルを自動切り替えする
毎回--profile フラグを手入力するのが手間な場合、.envファイルの COMPOSE_PROFILES 変数を使えばデフォルトのプロファイルを設定できます。# 開発環境の .env(Gitにコミットしない) COMPOSE_PROFILES=dev MYSQL_ROOT_PASSWORD=rootpassword MYSQL_DATABASE=wordpress MYSQL_USER=wpuser MYSQL_PASSWORD=wppassword
# --profileフラグなしでも .env の COMPOSE_PROFILES が適用される $ docker compose up -d [+] Running 4/4 ✔ Container wordpress-compose-db-1 Started ✔ Container wordpress-compose-wp-1 Started ✔ Container wordpress-compose-phpmyadmin-1 Started
COMPOSE_PROFILES=dev,debug)。注意:.envファイルにはパスワードが含まれるため、
.gitignore に追加してリポジトリにコミットしないよう必ず管理してください。開発効率を上げる|docker compose watchでホットリロード環境を作る
WordPress環境が起動できたら、次は開発フローを効率化してみましょう。Docker Compose v2.22から正式搭載された
docker compose watch は、ホスト側のファイル変更を監視して、コンテナへの自動同期や再ビルドをComposeネイティブに行う機能です。従来のbind mountでは、node_modulesの競合やmacOS・Windows環境での速度低下が問題になることがありましたが、watchはそれらを回避しながら高速な開発ループを実現します。
PHPテーマやプラグインの開発をWordPressコンテナ上で行う場合、watchを使えばファイルを保存するだけでコンテナ内のファイルが更新されます。従来のように「変更のたびにコンテナを停止・再起動する」ループから解放されます。
1. docker compose watchの動作条件
watchを使うには以下の条件を満たす必要があります。・Docker Engine 24.0以上(Docker CE 24.0以降 または Docker Desktop 4.24以降)
・Docker Compose v2.22以上
・compose.ymlの各サービスに
develop.watch ブロックを追加するバージョン確認は次のコマンドで行います。
$ docker compose version Docker Compose version v2.27.1
v2.22.0 以上が表示されれば docker compose watch が使えます。それ以前のバージョン(v2.21以下)では watch サブコマンドが存在しないためエラーになります。2. watchの3つのアクション
watchブロックでは、変更検知時の動作をaction で指定します。・sync:ホストのファイルをコンテナ内の指定パスへコピーします。コンテナの再起動は発生しません。ソースコードやテンプレートの変更に最適です
・rebuild:
docker build を再実行してコンテナを作り直します。依存関係ファイル(requirements.txtやpackage.json等)が変わった時に使います・sync+restart:ファイルを同期してからコンテナを再起動します。設定ファイル(nginx.conf・.env等)の変更に向いています
| アクション | 動作 | 主な用途 |
|---|---|---|
| sync | ファイルをコンテナに転送(再起動なし) | JS・PHP・Pythonのソースコード変更 |
| rebuild | イメージ再ビルドしてコンテナ差し替え | package.json・requirements.txtの変更 |
| sync+restart | ファイル転送後にコンテナ再起動 | 設定ファイル・.envの変更 |
3. compose.ymlにwatch設定を追加する
WordPressのテーマ開発を例に、compose.ymlにwatchを追加する方法を示します。wordpressサービスに
develop.watch ブロックを追加します。services: db: image: mysql:8.0 # ... (前述のdb設定と同じ) wordpress: image: wordpress:6.5-php8.3-apache restart: always depends_on: db: condition: service_healthy ports: - "8080:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wpuser WORDPRESS_DB_PASSWORD: wppassword WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html develop: watch: - action: sync path: ./themes/my-theme target: /var/www/html/wp-content/themes/my-theme ignore: - "*.log" volumes: db_data: wp_data:
・target:コンテナ内のコピー先パス
・ignore:監視対象から除外するパターン(.dockerignoreと同じ書式)
ホスト側の
./themes/my-theme ディレクトリをあらかじめ作成しておき、そこにWordPressテーマファイルを配置してください。PHPファイルやCSSを保存すると、コンテナ内の対応するパスへ自動的にコピーされます。
4. docker compose watchを起動する
compose.ymlを編集したら、次の順で起動します。# コンテナをバックグラウンドで起動 $ docker compose up -d # watchを開始(フォアグラウンド動作。Ctrl+Cで停止) $ docker compose watch Watch enabled Watching...
# themes/my-theme/style.css を保存するとsyncが自動実行される syncing service "wordpress" after changes were detected
docker compose up --watch と書けばコンテナ起動とwatch開始を1コマンドで行えます。開発時はこちらのほうが1ステップ省けて便利です。5. Node.jsアプリへのwatch適用例(Express + nodemon)
WordPressに限らず、Node.jsやPythonのアプリ開発にもwatchは活用できます。Node.jsの場合、
nodemon と組み合わせることで、syncで転送されたファイルをnodemonが検知して自動再起動します。ソースコードの変更はsyncで高速に反映し、package.jsonが変わった時だけrebuildが走る設計です。# compose.yml(Node.js + nodemon) services: api: build: context: . target: development ports: - "3000:3000" develop: watch: - path: ./src action: sync target: /app/src ignore: - node_modules - path: package.json action: rebuild - path: .env action: sync+restart target: /app/.env
# Dockerfile(マルチステージ・開発と本番を分離) FROM node:20-slim AS base WORKDIR /app COPY package*.json ./ RUN npm ci FROM base AS development RUN npm install -g nodemon COPY src/ ./src/ CMD ["nodemon", "src/app.js"] FROM base AS production RUN npm ci --only=production COPY src/ ./src/ CMD ["node", "src/app.js"]
node_modules を指定することが重要です。コンテナ内の依存関係(npm ciでインストールされたもの)をホスト側の変更から保護し、node_modulesの競合を防ぎます。compose.ymlの target: development で開発用ステージを指定することで、本番用Dockerfileをそのまま使いながら開発環境を分離できます。6. PythonアプリへのWatch適用例(FastAPI + uvicorn)
Pythonの場合はuvicorn --reload と組み合わせるとよいです。syncで転送されたファイルをuvicornが検知して自動再起動します。# compose.yml(FastAPI + uvicorn --reload) services: api: build: . ports: - "8000:8000" develop: watch: - path: ./app action: sync target: /app/app ignore: - __pycache__ - "*.pyc" - path: requirements.txt action: rebuild
[tomohiro@dev01 ~/fastapi-app]$ docker compose up --watch [+] Running 1/1 ✔ Container fastapi-app-api-1 Started Watch enabled - watch path ./app target /app/app action sync - watch path requirements.txt action rebuild # ./app/main.pyを編集して保存したときの出力 Syncing "app/main.py" after change INFO: Reloading... INFO: Application startup complete.
7. bind mountとwatchの使い分け
bind mountとwatchはどちらも「ホストのファイル変更をコンテナに反映する」仕組みですが、設計思想が異なります。| 比較項目 | bind mount | docker compose watch(sync) |
|---|---|---|
| 設定の簡単さ | volumes: でワンライン | develop.watchブロックが必要 |
| node_modules競合 | 起きやすい | ignoreで明示的に除外できる |
| macOS・Windows速度 | 低速(osxfs / WSL2経由) | ネイティブコピーで高速 |
| 本番との差異 | ホストのファイルを直接参照 | Dockerfileベースのイメージに近い |
| 必要なComposeバージョン | 全バージョン | v2.22以上 |
トラブルシューティング|よくあるエラーと解決策
1. 「Error response from daemon: Ports are not available」
ホストの8080番ポートがすでに使われている場合に発生します。Linux ポート確認の全コマンドで紹介しているss/lsofコマンドを使って、現在のポート使用状況を確認しましょう。
# 使用中のポートを確認 $ ss -tlnp | grep 8080 # 別のポートに変更する(例: 8081) # docker-compose.yml の ports セクションを変更 ports: - "8081:80"
2. WordPressが「データベース接続の確立エラー」を表示する
depends_onだけではMySQLの内部初期化完了まで保証されません。本記事の構成ではhealthcheckで対策済みですが、healthcheckなしのyamlを使っている場合に発生することがあります。
# ログでMySQLの初期化状況を確認 $ docker compose logs db | tail -20 # 「ready for connections」が表示されるまで待ってからWordPressにアクセスする 2024-06-26T10:23:45.123456Z 1 [System] [MY-011011] [Server] ready for connections. Version: '8.0.37'
それでも解消しない場合は、healthcheckを追加してdepends_onの条件をservice_healthyに変更してください。
3. docker compose up が「yaml: line X: did not find expected key」で失敗する
docker-compose.ymlのインデントが崩れている場合に発生します。YAMLはインデントにスペースのみ使用します(タブ文字は禁止)。
# yamlの構文チェック(エラーがなければ展開済みの設定が出力される) $ docker compose config name: wordpress-compose services: db: ...
4. 「permission denied while trying to connect to the Docker daemon socket」
一般ユーザーでdockerグループに属していない場合に発生します。# 自分のユーザーをdockerグループに追加 $ sudo usermod -aG docker $USER # 再ログインまたはグループを即時反映 $ newgrp docker # 確認 $ groups | grep docker user_name docker
5. 「Cannot connect to the Docker daemon」でcomposeが起動しない
Dockerデーモン自体が停止している場合に発生します。Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
# デーモンの状態を確認する $ sudo systemctl status docker # 停止していれば起動する $ sudo systemctl start docker # 自動起動が無効になっていれば有効化する $ sudo systemctl enable docker
Linux DNS 設定の基本を理解しておくと、本番環境でのドメイン設定や名前解決の仕組みが分かり、Dockerコンテナのネットワーク設計にも応用できます。
6. docker compose watchで「unknown flag: --watch」が出る
Docker Composeのバージョンが古い(v2.21以下)場合に発生します。docker compose version でバージョンを確認し、v2.22以上にアップデートしてください。# Ubuntu 24.04でのアップデート $ sudo apt-get update && sudo apt-get install docker-compose-plugin # Rocky Linux 9でのアップデート $ sudo dnf update docker-compose-plugin # バージョン確認 $ docker compose version Docker Compose version v2.27.1
7. ファイルを保存してもsyncのメッセージが出ない
watchブロックのpath が実際のディレクトリと一致していない場合に発生します。pathはcompose.ymlがあるディレクトリを起点とした相対パスで指定します。
# NG: ホストの絶対パスを指定している - path: /home/tomohiro/myapp/src # OK: compose.ymlからの相対パスで指定する - path: ./src # compose.yml があるディレクトリで存在確認 $ ls -la ./themes/my-theme/ total 28 drwxr-xr-x 2 user user 4096 Jul 24 10:00 . drwxr-xr-x 5 user user 4096 Jul 24 09:00 .. -rw-r--r-- 1 user user 512 Jul 24 10:00 style.css
docker compose versionでv2.22以上かを必ず確認してください。注意: docker composeコマンドとdocker-composeコマンド(旧式・ハイフン版)はバージョン体系が異なります。watchに対応しているのは
docker compose version(スペース区切り)がv2.22以上の場合のみです。ハイフン版のdocker-composeはv1系であり、watchには対応していません。8. ファイルは同期されているのにアプリに変更が反映されない
コンテナ内のアプリ自体がホットリロードに対応していない場合に発生します(静的なプロセスが起動したまま)。syncアクションはファイルの転送を担当するだけで、転送後のプロセス再起動は各言語・フレームワーク側の仕組みに委ねられています。
・Python Flask:
flask run --reload または FLASK_DEBUG=1 を設定する・Node.js:起動コマンドを
nodemon に変える・設定ファイル変更の場合:
action: sync ではなく action: sync+restart を使う9. 「Bind for 0.0.0.0:8080 failed: port is already allocated」(--scaleで発生)
docker compose up --scale でWordPressを複数台起動しようとした際、ports: "8080:80" のようにホストポートを固定しているサービスで発生するエラーです。# NG:ホストポートを固定するとスケール不可(2台目でエラー) ports: - "8080:80" # OK:コンテナポートのみ公開(ホスト側はDockerが自動割当) ports: - "80"
10. 「input device is not a TTY」が出る(docker compose run)
docker compose run をパイプやCIスクリプトから呼び出した場合に発生します。-T(--no-TTY)オプションを付けて非対話モードで実行してください。# NG: CIでパイプに渡す際にTTYエラーが出る $ docker compose run --rm app pytest tests/ | tee results.txt the input device is not a TTY # OK: -T を付けて非対話モードで実行する $ docker compose run --rm -T app pytest tests/ | tee results.txt
11. docker compose runした停止コンテナが溜まっている
--rm を付けずに docker compose run を繰り返すと、停止状態のコンテナが積み重なりディスクを圧迫します。次のコマンドで確認・一括削除できます。# 停止済みコンテナを確認する $ docker ps -a --filter "status=exited" CONTAINER ID IMAGE COMMAND STATUS d4a9e7f1... app-web "python manage.py" Exited (0) 2 hours ago app-web-run-1 a1b2c3d4... app-web "pytest tests/" Exited (0) 1 hour ago app-web-run-2 # 停止済みコンテナをまとめて削除する $ docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y Total reclaimed space: 128MB # 今後は --rm を付ける $ docker compose run --rm web python manage.py migrate
12. profilesを設定したのにサービスが起動しない
# 症状: phpmyadminが起動しない $ docker compose up -d $ docker compose ps # phpmyadmin が一覧に表示されない
--profile dev の指定を忘れている。または .env に COMPOSE_PROFILES が設定されていない。原因2:compose.ymlの
profiles: のインデントが崩れている。docker compose config で展開後の設定を確認します。# 設定の展開結果を確認(インデントミスの検出に有効) $ docker compose --profile dev config # profilesサービスも含めて全コンテナを削除する場合 $ docker compose --profile dev down
まとめ
この記事で解説したDocker ComposeによるWordPress環境構築と開発効率化の手順をまとめます。| 手順 | 操作内容 |
|---|---|
| インストール確認 | docker compose version でv2を確認する |
| 作業ディレクトリ作成 | mkdir ~/wordpress-compose を作成してcdで移動する |
| yaml作成 | docker-compose.ymlにdb・wordpressサービスとボリュームを定義する |
| healthcheck追加(推奨) | MySQLサービスにhealthcheckを設定し、depends_onをservice_healthyにする |
| 起動 | docker compose up -d でバックグラウンド起動する |
| 状態確認 | docker compose ps でSTATUS=Up (healthy)を確認してブラウザでアクセスする |
| 一時タスク実行(マイグレーション等) | docker compose run --rm -T サービス名 コマンド で実行して完了後に自動削除する |
| スケールアウト | docker compose up --scale wordpress=3 -d で複数台に増やす |
| 台数の固定定義 | deploy.replicas: 3 をdocker-compose.ymlに記述する |
| プロファイル指定起動 | docker compose --profile dev up -d で開発専用サービスを含めて起動する |
| .envでプロファイル自動設定 | COMPOSE_PROFILES=dev(.envに記述)でコマンドを変えずにプロファイルを適用する |
| ホットリロード設定 | compose.ymlにdevelop.watchブロックを追加して docker compose watch を実行する |
| 停止・削除 | docker compose down でコンテナとネットワークを削除する |
WordPressのような「Webサーバー+DB」の組み合わせはComposeが最も力を発揮する典型的なユースケースです。
さらに
docker compose run でDBマイグレーションやテストをワンショット実行し、--scale や deploy.replicas でコンテナ数を柔軟に調整し、profiles で開発・本番のサービス構成を1ファイルで管理し、docker compose watch のsync・rebuild・sync+restartを使い分けることで、ファイル変更を即座に反映できる高速な開発環境が整います。まずは今回の構成を手元で動かし、yamlを少しずつ変えながら理解を深めていきましょう。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、本記事で紹介したDocker Composeの構築手順を、さらに深く学べる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
次に読む記事
Docker・Linuxの理解をさらに深めたい方に、以下の記事もおすすめです。【コンテナ基礎】
・Linuxでdockerを使う入門|コンテナ技術の基礎を初心者向けに解説
【ネットワーク診断】
・Linuxのポート状況を確認するコマンド|ss・lsof・netstatの使い方
【ストレージ・マウント】
・mountコマンドの使い方|デバイスをマウント・アンマウントする方法
【DNS・名前解決】
・LinuxのDNS設定の基本|resolv.confと名前解決の仕組みを解説
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 次のページへ:Dockerfileの書き方入門|自分のアプリをイメージ化する基礎と注意点
- 前のページへ:LinuxにNginxをインストールして使う入門・Ubuntu・WSL2でウェブサーバーを構築して初めてのHTMLページを表示する方法
- この記事の属するカテゴリ:【Linux入門】初心者のための基礎知識・講座へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます