2026年7月18日

2026年7月18日

Dockerのバインドマウントの使い方|ボリュームとの違いと権限・パスのつまずき対処

バインドマウントは、ホスト上のディレクトリやファイルをそのままコンテナ内のパスに見せる仕組みです。ホストで編集したファイルがすぐコンテナに反映されるため、WordPressのテーマやプラグインの開発、設定ファイルの差し込みに向いています。一方で、データの永続化だけが目的なら名前付きボリュームのほうが扱いやすい場面も多くあります。この記事では、-v と --mount の書き方の違い、Composeでの指定、ボリュームとの使い分け、権限やパスでつまずいたときの調べ方を説明します。

コマンドはDocker Engine 27系以降とCompose v2(docker compose)を前提にしています(2026年10月現在)。

バインドマウントとボリュームの違い

どちらもコンテナを削除してもデータが残る点は同じですが、「データをどこに置き、誰が管理するか」が違います。

  • バインドマウント:ホストの任意のパスをマウントします。中身はホスト側のファイルそのもので、ホストのエディタやgitでそのまま扱えます。その代わり、ホストのディレクトリ構成・所有者・権限にコンテナが左右されます。
  • 名前付きボリューム:Dockerが管理する領域(Linuxでは通常 /var/lib/docker/volumes/ 配下)に作られます。docker volume コマンドで作成・削除・一覧ができ、ホストのパスを意識せずに済みます。DBのデータディレクトリのように、人が直接触らないデータに向いています。

もう一つ重要な違いが、マウント先に元からファイルがある場合の挙動です。空の名前付きボリュームをマウントすると、イメージ内のそのパスにあったファイルがボリュームにコピーされます。バインドマウントではコピーは起こらず、ホスト側のディレクトリの内容でマウント先が覆い隠されます。たとえば空のホストディレクトリを /var/www/html にバインドマウントすると、イメージに入っていたファイルは見えなくなります。「マウントしたらアプリのファイルが消えた」という相談の多くはこれです(イメージの中身は消えておらず、見えなくなっているだけです)。

開発中のソースコードや、ホスト側で管理したい設定ファイルはバインドマウント、DBや本番のアップロードファイルのように実行時に増えるデータは名前付きボリューム、と分けるのが基本です。

docker runでの指定方法

指定方法は -v(--volume)と --mount の2通りあります。

# -v 形式(ホストのパス:コンテナのパス[:オプション])
docker run -d --name web -p 8080:80 \
  -v "$(pwd)/html:/usr/share/nginx/html:ro" \
  nginx:1.27-alpine

# --mount 形式(キー=値で指定)
docker run -d --name web -p 8080:80 \
  --mount type=bind,source="$(pwd)/html",target=/usr/share/nginx/html,readonly \
  nginx:1.27-alpine

ホスト側のパスは / から始まるフルパスで書きます。-v html:/usr/share/nginx/html のように / や ./ で始まらない名前を書くと、それはパスではなく「html という名前のボリューム」と解釈され、空のボリュームが作られてしまいます。カレントディレクトリを基準にしたいときは、上の例のように $(pwd) を使うと確かです。

-v と --mount には、ホスト側のパスが存在しないときの挙動にも違いがあります。-v はホスト側にディレクトリを自動で作ってしまう(root所有の空ディレクトリになる)のに対し、--mount はエラーで止まります。パスの打ち間違いに気づきやすいのは --mount です。

:ro(--mount では readonly)を付けると、コンテナからは読み取り専用になります。Nginxの設定ファイルや公開用の静的ファイルなど、コンテナ側から書き換える必要がないものには付けておくと、コンテナが乗っ取られた場合でもホストのファイルを改ざんされにくくなります。

Docker Composeでの指定方法

Composeでは volumes に書きます。短い書式と長い書式があり、相対パスはcomposeファイルのあるディレクトリが基準になります。

services:
  wordpress:
    image: wordpress:php8.3-apache
    ports:
      - "8080:80"
    volumes:
      # テーマ開発用:ホストのディレクトリを直接マウント
      - ./themes/mytheme:/var/www/html/wp-content/themes/mytheme
      # PHP設定の差し込み(読み取り専用)
      - type: bind
        source: ./php/uploads.ini
        target: /usr/local/etc/php/conf.d/uploads.ini
        read_only: true
      # WordPress本体とアップロードは名前付きボリューム
      - wp_data:/var/www/html

volumes:
  wp_data:

この構成では、WordPress本体は名前付きボリュームに置き、開発中のテーマだけをバインドマウントで上から重ねています。/var/www/html 全体をバインドマウントすると、本体の更新やプラグインのインストールのたびにホスト側のファイルが書き換わり、権限の問題も起きやすくなるため、触りたい部分だけをマウントするほうが管理しやすくなります。

ボリュームの中にさらにバインドマウントを重ねる場合、より深いパスのマウントが優先されます。上の例では wp-content/themes/mytheme だけがホスト側の内容になり、ほかは wp_data の内容が見えます。

権限エラーへの対処

バインドマウントで最も多いトラブルが権限です。コンテナ内のプロセスは、ホストと同じ数値のUID/GIDでファイルにアクセスします。ユーザー名ではなく番号で判定される点がポイントです。

公式の wordpress イメージ(Debianベース)では、Apacheは www-data(UID 33)で動きます。ホストで作業しているユーザーが UID 1000 なら、ホストで作ったディレクトリにコンテナのApacheは書き込めず、メディアのアップロードやプラグインの更新が失敗します。

確認は、ホストとコンテナの両方から番号で見ると早いです。

# ホスト側(数値で表示)
ls -ln ./themes/mytheme

# コンテナ側
docker compose exec wordpress ls -ln /var/www/html/wp-content/themes/mytheme
docker compose exec wordpress id www-data

対処はいくつかあります。

  • コンテナから書き込む必要があるディレクトリだけ、所有グループを合わせて書き込み権限を付ける(例:sudo chgrp -R 33 ./uploads && chmod -R g+w ./uploads)。
  • コンテナから書き込む必要がないなら :ro でマウントし、ホスト側だけで編集する。
  • 実行時に増えるデータは、そもそも名前付きボリュームに置く。

chmod -R 777 で解決したくなりますが、同じサーバー上のほかのユーザーやプロセスからも書き換えられる状態になるため、避けてください。所有者を変更する前には、元の状態を ls -ln で控えておくと戻せます。

SELinuxが有効なディストリビューション(RHEL系など)では、所有者や権限が正しくても「Permission denied」になることがあります。この場合はマウント指定に :z(複数コンテナで共有)または :Z(そのコンテナ専用)を付けると、Dockerがラベルを付け直します。:Z をホームディレクトリや /etc のようなシステムのディレクトリに付けるとホスト側から使えなくなることがあるので、専用のディレクトリにだけ使ってください。

ファイル単体のマウントで変更が反映されない

nginx.conf のようにファイル単体をバインドマウントしていると、ホストで編集したのにコンテナ内の内容が古いまま、ということがあります。バインドマウントはファイルのinode(実体)に結びついているため、エディタや sed -i が「新しいファイルを書いて置き換える」方式で保存すると、コンテナは古いinodeを見続けるからです。

確実さを求めるなら、ファイルではなくそのファイルを含むディレクトリをマウントするのが一番の対策です。ファイル単体のままにする場合は、編集後に docker compose restart nginx でコンテナを再起動すると新しい内容が見えます。

Docker DesktopとWSL2での注意

MacやWindowsのDocker Desktopでは、コンテナはLinuxの仮想マシン上で動き、ホストのファイルは共有の仕組みを通して見えます。そのため、ファイル数の多いディレクトリ(node_modules や vendor、WordPress本体)をバインドマウントすると、Linuxサーバー上より読み書きが遅くなります。

Windowsでは、プロジェクトを C:\ 側(WSLからは /mnt/c/...)ではなく、WSL2のLinuxファイルシステム(~/projects など)に置くと速度の差が大きく縮まります。ファイル変更の検知(ホットリロード)が効かない場合も、WSL側に置くことで解消することがあります。

マウントの状態を確認する方法

意図どおりにマウントされているかは、docker inspect で確認できます。

docker inspect -f '{{ json .Mounts }}' web

出力の Type が bind か volume か、Source がホストのどのパスか、RW が読み書き可能か(false なら読み取り専用)を見ます。Source が想定と違うパスになっている、あるいは Type が volume になっている場合は、パスの書き方(./ の有無など)を見直してください。

まとめ

  • バインドマウントはホストのパスをそのままコンテナに見せる。開発中のコードや設定ファイル向き。実行時に増えるデータは名前付きボリュームに置く。
  • バインドマウントはマウント先の既存ファイルを覆い隠す。空のボリュームのようにイメージの中身がコピーされることはない。
  • -v は存在しないホストパスを自動作成し、--mount はエラーにする。/ や ./ で始まらない指定はボリューム名と解釈される。
  • 権限はUID/GIDの番号で判定される。ls -ln で双方を確認し、777 ではなくグループ権限や :ro、ボリュームで解決する。SELinux環境では :z / :Z を検討する。
  • ファイル単体のマウントは編集が反映されないことがあるため、ディレクトリ単位でマウントする。
  • 状態は docker inspect の Mounts で確かめる。

お気軽にご相談ください

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