2026年6月30日

2026年6月30日

DockerのボリュームマウントでWordPress開発環境のデータを永続化する方法

DockerでWordPressの開発環境を作るときは、「データベースは名前付きボリューム」「自分が編集するテーマ・プラグインはバインドマウント」と使い分けると、コンテナを作り直してもデータが消えず、エディタでの編集もすぐ反映される環境になります。この記事では、ボリュームの種類と使い分け、Docker Composeでの具体的な構成、データが消える典型的な操作、権限エラーへの対処、バックアップと復元の手順を説明します。

Docker や公式イメージの仕様は更新されることがあります。以下は執筆時点(2026年10月現在)の Docker Compose(docker compose コマンド、Compose V2)を前提にした例です。

なぜ永続化が必要なのか

コンテナの中で書き換えたファイルは、そのコンテナを削除すると一緒に消えます。WordPressの開発環境でいえば、記事や設定が入ったデータベース、アップロードした画像、インストールしたプラグインが、docker compose down のあと作り直すたびに初期状態に戻ってしまいます。

これを防ぐのがボリュームです。コンテナの外にデータの置き場所を作り、コンテナの特定のディレクトリにつなぐ(マウントする)ことで、コンテナを作り直してもデータが残ります。

3種類のマウントと使い分け

Dockerのマウントには主に次の3種類があります。

  • 名前付きボリューム(named volume): Dockerが管理する保存領域。中身をホスト側で直接編集することは想定していませんが、性能が安定していて、権限の問題も起きにくいのが特長です。データベースのデータに向いています。
  • バインドマウント(bind mount): ホストの特定のフォルダをそのままコンテナにつなぐ方法。ホスト側のエディタで編集した内容がすぐコンテナに反映されるので、開発中のテーマやプラグインに向いています。
  • tmpfs マウント: メモリ上の一時領域。永続化には使えません。

WordPressの開発環境では、次の組み合わせが扱いやすい構成です。

対象 コンテナ内のパス マウントの種類
データベース /var/lib/mysql 名前付きボリューム
WordPress本体 /var/www/html 名前付きボリューム
開発中のテーマ・プラグイン /var/www/html/wp-content/themes/テーマ名 など バインドマウント

WordPress本体まで丸ごとバインドマウントする方法もありますが、コアファイルを手元に置くと検索やGit管理の対象が増え、macOS や Windows では読み書きが遅くなりがちです。自分で編集する部分だけをバインドマウントにすると、見通しのよい構成になります。

Docker Composeの構成例

公式の wordpress イメージと mariadb イメージを使う例です。パスワードはダミーなので、自分の環境用に変更してください。

# compose.yaml
services:
  db:
    image: mariadb:11
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wpuser
      MARIADB_PASSWORD: change-me
      MARIADB_ROOT_PASSWORD: change-me-root
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5

  wordpress:
    image: wordpress:php8.3-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: change-me
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DEBUG: "1"
    volumes:
      - wp_data:/var/www/html
      - ./themes/my-theme:/var/www/html/wp-content/themes/my-theme
      - ./plugins/my-plugin:/var/www/html/wp-content/plugins/my-plugin

volumes:
  db_data:
  wp_data:

ポイントを順に見ていきます。

  • **db_data**: データベースの中身を保存する名前付きボリュームです。初回起動時に MARIADB_DATABASE などの値でデータベースとユーザーが作られます。これらの環境変数はボリュームが空のときの初回だけ使われるため、あとからパスワードを変えても反映されない点に注意してください。
  • **wp_data**: WordPress本体です。公式イメージは、マウント先が空のときに WordPress のファイルをコピーします。2回目以降は既存のファイルをそのまま使います。
  • バインドマウント: ./themes/my-theme のように、手元のテーマのフォルダだけをつないでいます。手元のフォルダが存在しないと、Dockerが空のフォルダを作ってしまうので、先にテーマのファイルを置いてから起動します。
  • **healthcheck と condition: service_healthy**: データベースの準備が整う前にWordPressが接続しにいくのを防ぎます。healthcheck.sh は公式 MariaDB イメージに含まれるスクリプトです。古いイメージを使う場合は存在しないことがあるので、使うイメージのドキュメントで確認してください。

起動は次のコマンドです。

docker compose up -d
docker compose ps        # 状態とヘルスチェックの結果を確認
docker volume ls         # 作成されたボリュームを確認

ボリューム名は、既定ではプロジェクト名(フォルダ名)が先頭に付いた myproject_db_data のような名前になります。フォルダ名を変えると別のボリュームとして扱われ、「データが消えた」ように見えることがあるため、プロジェクト名を固定したい場合は compose.yaml の先頭に name: myproject を書いておきます。

データが消える操作に注意する

永続化しても、次の操作をするとデータは消えます。

  • docker compose down -v:-v を付けると、Composeファイルで定義した名前付きボリュームも削除されます。普段の停止は docker compose down(-v なし)か docker compose stop を使います。
  • docker volume prune:どのコンテナからも使われていないボリュームを削除します。コンテナを消したあとに実行すると、残しておきたかったボリュームまで消える可能性があります。
  • 匿名ボリューム:volumes: でパスだけを書いた(名前を付けていない)ボリュームは、作り直すたびに新しく作られ、古いデータが見つけにくくなります。永続化したいものには名前を付けます。

逆に、開発中に「まっさらな状態に戻したい」ときは、意図して docker compose down -v を使えます。その前に、次の節の方法でバックアップを取っておくと安心です。

権限エラーへの対処

バインドマウントでよく起きるのが、ファイルの所有者の食い違いです。公式の wordpress イメージ(Debian系)では、Webサーバーは www-data(UID 33)として動きます。Linuxのホストで、手元のユーザーが作ったフォルダをマウントすると、WordPress がそのフォルダに書き込めず、テーマの更新やファイルの生成で失敗することがあります。

  • 開発中のテーマは、通常WordPressから書き込む必要がないので、読み取りができれば十分です。
  • WordPressから書き込みが必要なフォルダ(uploads など)は、名前付きボリュームに置くと権限の問題が起きにくくなります。
  • chmod 777 で解決するのは避けてください。開発環境でも、その設定が本番に持ち込まれる原因になります。

WP-CLI を使う場合、wordpress:cli イメージは Alpine 系で、www-data の UID が Debian 系と異なります。同じボリュームを扱うと権限エラーになることがあるため、UID をそろえて実行します。

  # compose.yaml の services: に追加する例
  wpcli:
    image: wordpress:cli
    user: "33:33"
    depends_on:
      - wordpress
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: change-me
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html
    profiles: ["tools"]
docker compose run --rm wpcli wp plugin list

profiles を付けておくと、docker compose up では起動せず、必要なときだけ実行できます。

macOS・Windowsでの速度

macOS や Windows の Docker Desktop では、バインドマウントの読み書きが Linux より遅くなる傾向があります。Windows では、プロジェクトのフォルダを WSL 2 の Linux 側のファイルシステム(\\wsl$\ 配下)に置くと、Windows 側のドライブに置くより速くなることが多いです。バインドマウントの範囲を開発中のテーマ・プラグインに絞るのも、速度対策として効果があります。

バックアップと復元

データベース

データベースはファイルをコピーするより、ダンプを取るほうが安全です。

# 書き出し(新しいMariaDBイメージでは mariadb-dump を使う)
docker compose exec -T db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" wordpress' > backup.sql

# 取り込み
docker compose exec -T db sh -c 'mariadb -u root -p"$MARIADB_ROOT_PASSWORD" wordpress' < backup.sql

-T は疑似端末を割り当てない指定で、出力をファイルに保存するときに余計な制御文字が混ざるのを防ぎます。MySQL イメージを使う場合は、コマンドを mysqldump と mysql、環境変数を MYSQL_ROOT_PASSWORD に読み替えます。

ボリュームを丸ごと保存する

名前付きボリュームの中身は、一時的なコンテナを使ってアーカイブにできます。データベースのボリュームを保存する場合は、書き込み中の不整合を避けるため、先に docker compose stop で止めてから行います。

docker run --rm \
  -v myproject_wp_data:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/wp_data.tar.gz -C /data .

復元は、空のボリュームに対して逆の操作(tar xzf)を行います。

WordPress本体の更新について

wp_data ボリュームにWordPress本体が入っている場合、イメージのタグを新しくしても、既存のボリューム内のWordPressは自動では置き換わりません。本体の更新は、管理画面の更新機能か wp core update で行います。PHPのバージョンはイメージのタグで決まるので、本番に合わせたタグを選んでおくと、本番との差による不具合を減らせます。

まとめ

  • データベースとWordPress本体は名前付きボリューム、編集するテーマ・プラグインはバインドマウントに分ける。
  • docker compose down -v と docker volume prune はボリュームを消す。普段の停止には使わない。
  • データベースの環境変数は初回のみ有効。プロジェクト名を固定してボリューム名の食い違いを防ぐ。
  • 権限エラーはUIDの違いが原因のことが多い。chmod 777 ではなくUIDをそろえる。
  • データベースはダンプで、ボリュームは一時コンテナと tar でバックアップする。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲