概要
バインドマウントとは、ボリュームマウントとは異なるタイプのマウントであり、ホスト上のファイルシステムをコンテナ内と直接共有する。
ホスト上のソースコードの変更をコンテナ上に直ちに反映することができる。
バインドマウント
バインドマウントを使用しない場合…
バインドマウントをせずにコンテナを起動する。
# Dockerイメージをビルドする。
$ docker build -t getting-started .
# コンテナを作成する。
$ docker run -dp 127.0.0.1:3000:3000 getting-started
Localhostの3000番からアプリケーションへのアクセスができるようになる。
この場合には、ホスト上のソースを修正しても、コンテナには反映されない。
Dockerイメージには、コンテナのファイルシステムの構成やアプリケーションのソースコード(ビルド済みの成果物の場合も)が含まれる。
コンテナ上で起動しているアプリケーションを最新にするには、コンテナを起動しているイメージを最新にする必要がある。
# イメージを再構築する。
$ docker image build -t getting-started .
# コンテナを再作成する。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
19bc26a99f56 cc9d6355b61f "docker-entrypoint.s…" About a minute ago Up About a minute 127.0.0.1:3000->3000/tcp tender_matsumoto
$ docker stop 19bc26a99f56
19bc26a99f56
$ docker rm 19bc26a99f56
19bc26a99f56
$ docker run -dp 127.0.0.1:3000:3000 getting-started
アプリケーションを最新にするには、イメージの再構築とコンテナの再起動が必要になる。
バインドマウント
バインドマウントを設定し、イメージを作り直す手間をなくす。
以下のコマンドでは、コンテナ起動時にバインドマウントを設定している。
$ docker run -dp 127.0.0.1:3000:3000 \
-w /app --mount type=bind,src="$(pwd)",target=/app \
node:18-alpine \
sh -c "yarn install && yarn run dev"
コマンドの詳細
-
-w
- 指定したディレクトリの中でコマンドを実行する。
- 今回の場合、
/app
ディレクトリ内でコマンドが実行される。
-
--mount type=bind,src="$(pwd)",target=/app
- マウントの種類を
bind
に指定する。 - ホスト上のカレントディレクトリをコンテナ内の
/app
ディレクトリにバインドマウントする。
- マウントの種類を
ファイルを変更すると、コンテナに直ちに反映される。
変更の度、nodemon
のプロセスが実行される。
$ docker logs -f a868ea16dfae
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.56s.
yarn run v1.22.19
$ nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
[nodemon] restarting due to changes...
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
疑問点
バインドマウントを設定した場合、ホストのファイルの変更時にDockerイメージが更新されているのか?
バインドマウントを使用しない場合は、ソースファイルの変更を適用するためにはイメージの再構築が必要になる。バインドマウントの場合もイメージを最新にする必要はないか?
結論
ソースを変更しても、イメージの更新は行われない。
# イメージの更新履歴を確認する。
$ docker image history getting-started
IMAGE CREATED CREATED BY SIZE COMMENT
b02659a4a713 12 minutes ago CMD ["node" "src/index.js"] 0B buildkit.dockerfile.v0
<missing> 12 minutes ago COPY . . # buildkit 4.59MB buildkit.dockerfile.v0
<missing> 13 days ago RUN /bin/sh -c yarn install --production # b… 85.2MB buildkit.dockerfile.v0
<missing> 13 days ago COPY package.json yarn.lock ./ # buildkit 148kB buildkit.dockerfile.v0
<missing> 2 weeks ago WORKDIR /app 0B buildkit.dockerfile.v0
<missing> 2 weeks ago /bin/sh -c #(nop) CMD ["node"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) COPY file:4d192565a7220e13… 388B
<missing> 2 weeks ago /bin/sh -c apk add --no-cache --virtual .bui… 7.77MB
<missing> 2 weeks ago /bin/sh -c #(nop) ENV YARN_VERSION=1.22.19 0B
<missing> 2 weeks ago /bin/sh -c addgroup -g 1000 node && addu… 114MB
<missing> 2 weeks ago /bin/sh -c #(nop) ENV NODE_VERSION=18.19.0 0B
<missing> 3 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:8182c73f869a899cf… 7.73MB
hisotry
からイメージの更新を観測することができる。
ファイルの更新をしても、イメージの更新履歴に変化はなかった。
なぜ、Dockerイメージが最新でないのにアプリケーションが更新されるのか?
空でないディレクトリにバインドマウントが行われる場合には、元のリソースが隠されて、バインドマウントされているソースが反映されるためである。
つまり、コンテナでは、ホスト上の最新のソースコードからアプリケーションの起動が行われている。
イメージを共有する場合には、Dockerイメージを最新にする必要がある。
空でないディレクトリへのマウント
空でないディレクトリにバインドマウントを行う場合、ディレクトリの元の内容が隠されることを注意しなければならない。
バインド マウント(bind mount) の使用 — Docker-docs-ja 24.0 ドキュメント
発生した事象
yarn run ${NODE_ENV}
の実施時に以下のエラーが発生した。
2024-03-25 00:32:59 Usage Error: Couldn't find the node_modules state file - running an install might help (findPackageLocation)
2024-03-25 00:32:59
2024-03-25 00:32:59 $ yarn run [--inspect] [--inspect-brk] [-T,--top-level] [-B,--binaries-only] [--require #0] <scriptName> ...
使用したDockerfile
FROM node:21.7.1-bullseye-slim
WORKDIR /app
# キャッシュ機能を有効活用するためにパッケージ関連のものを先にCOPYしている。
COPY yarn.lock package.json .yarnrc.yml .
COPY .yarn/ ./.yarn/
RUN yarn install
COPY . .
CMD yarn run ${NODE_ENV}
ここで意識するべき箇所は、/app
ディレクトリに依存関係のファイルがコピーされ、yarn install
によりnode_modules
が作成されているという点。
Dockerコンテナの起動コマンド
$ docker run \
-dp 127.0.0.1:3000:3000 \
--env NODE_ENV=dev \
--name web_container \
--mount type=bind,source=./web,target=/app \
web_container
/app
ディレクトリにバインドマウントが行われている。
空でないディレクトリへのバインドマウントが行われたため、元の内容が隠されてしまっている。
つまり、yarn install
で作成されたnode_modules
が参照できない。
問題の解消
問題の解消方法はものすごく単純でボリュームマウントを行う対象のディレクトリを変更すればいい。
/web
ディレクトリごとマウントしているが、/web
ディレクトリに含まれる個別のディレクトリごとに複数マウントする様に変更した。
$ docker run -dp 127.0.0.1:3000:3000 \
--env NODE_ENV=dev \
--name web_container \
--mount type=bind,source="$(pwd)/public",target=/app/public \
--mount type=bind,source="$(pwd)/src",target=/app/src \
web