Dockerのマウント先にファイルがあるとどうなる?挙動の違いを実機検証

Dockerのマウント先にファイルがあるとどうなる?挙動の違いを実機検証

2025.04.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Dockerを使っていると、ボリュームやホストディレクトリのマウント先にあるファイルがどのように扱われるのか、意外と挙動が分からなくなると感じる場面があります。
特に「イメージ側に既にファイルがある場合」「マウント元が空である場合」など、細かい違いが動作に影響するため、明確に理解しておくことが大切です。

本記事では、Dockerボリュームとホストディレクトリのマウントに関して、マウント元の状態によってどのようにマウント先が変化するのかを検証し、整理した結果を共有します。

挙動だけ知りたい

マウント種別 マウント元の状態 イメージ内のファイルは見えるか マウント先の中身
ホストディレクトリ(バインドマウント) ファイルあり ❌ 見えない ホストのファイル
ホストディレクトリ(バインドマウント) 空 ❌ 見えない 空(ホストディレクトリ)
Dockerボリューム ファイルあり ❌ 見えない ボリューム内のファイル
Dockerボリューム 空 ✅ 見える イメージ内のファイル(ボリュームにコピーされたもの)

続いてこの内容を実機で検証してみます。

マウント元にファイルがある場合

準備

まずイメージを作ります。

% cat Dockerfile
FROM busybox

RUN mkdir -p /mnt/host 
RUN echo "This is file in image" > /mnt/host/a.txt
RUN echo "This is file in image" > /mnt/host/b.txt
RUN mkdir -p /mnt/volume
RUN echo "This is file in image" > /mnt/volume/a.txt 
RUN echo "This is file in image" > /mnt/volume/b.txt

Dockerボリュームをマウントするディレクトリ、ホストディレクトリをマウントするディレクトリを作り、それぞれイメージ内に存在するとわかるファイル、a.txtとb.txtを作っています。
イメージをビルド & コンテナを起動して中身を確認してみましょう。

% docker build -t mount_test .
% docker run --rm  mount_test tree /mnt
/mnt
├── host
│   ├── a.txt
│   └── b.txt
└── volume
    ├── a.txt
    └── b.txt

次にホスト側です。
ホストディレクトリ内に存在するとわかるファイル、b.txtとc.txtを作ります。

% mkdir -p test_host_dir
% echo "This is file in host" > test_host_dir/b.txt
% echo "This is file in host" > test_host_dir/c.txt

一応確認します。

% tree test_host_dir 
test_host_dir
├── b.txt
└── c.txt

1 directory, 2 files

% cat test_host_dir/*.txt
This is file in host
This is file in host

次にボリュームです。ボリュームを作成し、ファイルを作ります。
ボリューム内に存在するとわかるファイル、b.txtとc.txtを作ります。

% docker volume create test_volume
% docker run --rm -v test_volume:/test_volume busybox sh -c \
    'echo "This is file in volume" > /test_volume/b.txt; \
     echo "This is file in volume" > /test_volume/c.txt'

volumeにファイルができているか確認しておきます。マウント先は一応変えて確認します。

% docker run --rm -v test_volume:/test_volume_confirm busybox sh -c \
    "tree /test_volume_confirm && \
     cat  /test_volume_confirm/*.txt"
/test_volume_confirm
├── b.txt
└── c.txt

0 directories, 2 files
This is file in volume
This is file in volume

マウントして確認してみる

% docker run --rm \
    -v test_volume:/mnt/volume \
    -v ./test_host_dir:/mnt/host mount_test \
    sh -c \
    "tree /mnt/host && cat /mnt/host/*.txt; \
     tree /mnt/volume && cat /mnt/volume/*.txt"

/mnt/host
├── b.txt
└── c.txt
0 directories, 2 files

This is file in host
This is file in host

/mnt/volume
├── b.txt
└── c.txt
0 directories, 2 files

This is file in volume
This is file in volume

ホストディレクトリのマウント先とDockerボリュームマウント先、いずれもa.txtがなく、b.txtとc.txt の中身から、イメージのファイルが見えなくなってホストディレクトリやボリュームの中身が見えるようになっていることが分かります。

マウント元にファイルがない場合

準備

イメージは先ほど作ったmount_testコンテナを流用しましょう。
一応、再度ディレクトリとファイルを確認しておきます。

% docker run --rm  mount_test sh -c "tree /mnt; cat /mnt/host/*.txt; cat /mnt/volume/*.txt"
/mnt
├── host
│   ├── a.txt
│   └── b.txt
└── volume
    ├── a.txt
    └── b.txt

2 directories, 4 files
This is file in image
This is file in image
This is file in image
This is file in image

ホスト側に空のディレクトリを作ります。

mkdir test_host_dir_empty

次に空のvolumeを作ります。

docker volume create test_volume_empty

マウントして確認してみる

まずホストディレクトリのマウントから確認してみましょう。

% docker run --rm \
    -v ./test_host_dir_empty:/mnt/host \
    mount_test \
    sh -c \
    "tree /mnt/host/; cat /mnt/host/*.txt"
/mnt/host/

0 directories, 0 files
cat: can't open '/mnt/host/*.txt': No such file or directory

マウント先にはファイルがありません。このことから、ホストディレクトリ内にファイルがある場合と同じく、image内のファイルが見えなくなってホストディレクトリが見えるようになっていることが分かります。

ではボリュームのマウントはどうでしょうか。

% docker run --rm \
    -v test_volume_empty:/mnt/volume \
    mount_test \
    sh -c \
    "tree /mnt/volume/; cat /mnt/volume/*.txt"
/mnt/volume/
├── a.txt
└── b.txt

0 directories, 2 files
This is file in image
This is file in image

お、ボリュームにファイルがある場合と結果が異なりますね。マウント先にはa.txtがあり、a.txt、b.txtの内容から、このファイルはimageにあったものだと分かります。
では、ボリューム内にファイルがない場合はイメージのディレクトリが見えるという挙動なのでしょうか。

ボリュームの中身を見てみます。マウント先は別のディレクトリにして確認しましょう。

% docker run --rm \
    -v test_volume_empty:/mnt/test_volume_confirm \
    mount_test \
    sh -c \
    "tree /mnt/test_volume_confirm; \
     cat /mnt/test_volume_confirm/*.txt"
/mnt/test_volume_confirm
├── a.txt
└── b.txt

0 directories, 2 files
This is file in image
This is file in image

空だったボリューム内に、イメージ内にあったファイルが存在します。
このことから、空のボリュームをマウントするとイメージ内のファイルがボリュームにコピーされていることが分かります。
先ほどのマウント確認でイメージのファイルが見えていたのは、イメージのディレクトリやファイルが直接見えているわけではなく、イメージの内容がコピーされたボリュームが見えてたんですね。

🗂️ Docker マウントの挙動比較表

今回確認した内容をまとめます。

マウント種別 マウント元の状態 マウント後の中身 イメージ内のファイルは? 備考
ホストディレクトリ ファイルあり(b.txt, c.txt) b.txt, c.txt 見えない マウント元の内容で上書きされる
ホストディレクトリ 空 空 見えない 空でもホストディレクトリが優先される
Dockerボリューム ファイルあり(b.txt, c.txt) b.txt, c.txt 見えない ボリューム内の内容が使われる
Dockerボリューム 空 a.txt, b.txt(イメージ由来) 見える(コピーされる) 初回マウント時のみイメージの内容がコピーされる

分かること

  • Dockerボリュームが 空のときのみ イメージ内のファイルがコピーされる。
  • (記事内では省略)一度ファイルが書き込まれたボリュームには、イメージ内のファイルは二度と反映されない。
  • ホストディレクトリをマウントした場合は、内容の有無に関係なくイメージ内は見えない(ホスト側が完全に優先される)。

おわりに

Dockerにおけるボリュームとホストディレクトリのマウントは、単に「マウントする」だけでは済まない微妙な挙動の違いがあります。

特に、Dockerボリュームは初回マウント時に限り、イメージ内のファイルがコピーされるという仕様は、知っているかどうかで何が起きているか調査する大きな手掛かりになるでしょう。

検証コードは手元で再現可能ですので、気になる方はぜひ試してみてください。

この記事をシェアする

関連記事