
Dockerのマウント先にファイルがあるとどうなる?挙動の違いを実機検証
はじめに
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ボリュームは初回マウント時に限り、イメージ内のファイルがコピーされるという仕様は、知っているかどうかで何が起きているか調査する大きな手掛かりになるでしょう。
検証コードは手元で再現可能ですので、気になる方はぜひ試してみてください。