docker composeにおけるvolumeの挙動
対象は以下の4パターン
- bind mountでホスト側が空の場合
- bind mountでホスト側が空ではない場合
- local bindなnamed volumeのvolume mountでホスト側が空の場合
- local bindなnamed volumeのvolume mountでホスト側が空ではない場合
Dockerfileはこちら
FROM alpine:3.20
RUN mkdir -p /app/bind-1 \
&& mkdir -p /app/bind-2\
&& mkdir -p /app/named-bind-1 \
&& mkdir -p /app/named-bind-2
RUN echo "file in bind1" > /app/bind-1/file.txt \
&& echo "file in bind2" > /app/bind-2/file.txt \
&& echo "file in named-bind-1" > /app/named-bind-1/file.txt \
&& echo "file in named-bind-2" > /app/named-bind-2/file.txt
CMD ["sh", "-c", "sleep infinity"]
これをmountなしで起動する。
docker build -t volume-test-app .
docker run --rm -it volume-test-app sh
当然こうなる。
/ # tree app
app
├── bind-1
│ └── file.txt
├── bind-2
│ └── file.txt
├── named-bind-1
│ └── file.txt
└── named-bind-2
└── file.txt
次に、docker composeで、先ほどあげたパターンでmountする。
services:
app:
build: .
volumes:
- ./host-bind-empty:/app/bind-1
- ./host-bind-non-empty:/app/bind-2
- named_bind_volume:/app/named-bind-1
- named_bind_volume2:/app/named-bind-2
volumes:
named_bind_volume:
driver: local
driver_opts:
type: none
o: bind
device: ./host-named-bind-empty
named_bind_volume2:
driver: local
driver_opts:
type: none
o: bind
device: ./host-named-bind-non-empty
host側はこんな感じ。
.
├── Dockerfile
├── docker-compose.yml
├── host-bind-empty #1
├── host-bind-non-empty #2
│ └── host-file.txt
├── host-named-bind-empty #3
└── host-named-bind-non-empty #4
└── host-named-bind-file.txt
実行。
docker compose build app
docker compose run --rm --no-deps app sh
コンテナ内を見るとこうなっている。
/ # tree app
app
├── bind-1 # イメージ内に存在したファイルが消えている。
├── bind-2 # ホスト側のファイルのみが存在する。
│ └── host-file.txt
├── named-bind-1 # イメージ内に存在したファイルがそのまま存在する。
│ └── file.txt
└── named-bind-2 # ホスト側のファイルのみが存在する。
└── host-named-bind-file.txt
ホスト側はこう。
tree
.
├── Dockerfile
├── docker-compose.yml
├── host-bind-empty # 空のまま。
├── host-bind-non-empty # 元のファイルがそのまま存在する。
│ └── host-file.txt
├── host-named-bind-empty # イメージ側のファイルが存在する。
│ └── file.txt
└── host-named-bind-non-empty # ホスト側のファイルがそのまま存在する。
└── host-named-bind-file.txt
bind mountの場合、コンテナ内にもともと存在するファイルやディレクトリはホスト側によって上書きされる。
https://docs.docker.com/engine/storage/bind-mounts/?utm_source=chatgpt.com#bind-mounting-over-existing-data
volume mountの場合、non-emptyなvolumeでマウントする場合は、bind mountと同様にホスト側によって上書きされる。しかし、emptyなvolumeでマウントする場合、コンテナ内に存在するファイルやディレクトリがコピーされる。
https://docs.docker.com/engine/storage/volumes/?utm_source=chatgpt.com#mounting-a-volume-over-existing-data
この挙動を利用すると、local bindなnamed volumeを定義して、そのvolumeでvolume mountをすることで、イメージ内にもともと存在するファイルをホスト側にコピーさせることが可能となる。
たとえばイメージビルド時にnpm installした内容をnode_modulesディレクトリを通じてホストと共有することできる。
その状態でコンテナ内で新たにnpm installすれば、ホスト側にもそれが共有される。