カテゴリー
docker-composeでマウントするvolumeを選択的にinclude/exclueする方法
※ 当ページには【広告/PR】を含む場合があります。
2023/09/23

Node.jsアプリ開発を進めていく過程で、だんだんとnpmパッケージが肥大化して、
node_modules
また開発用のDockerコンテナと、実行環境だけをまとめたコンテナの2つがある場合、それぞれに同じ内容のnpmパッケージを個別にインストールするよりも、共通のボリュームを作成して、そこに
node_modules
今回はDockerのコンテナ起動時にホスト側からリソースをマウントする際のinclude/excludeの基本を解説していきます。
Dockerコンテナで使う「Volume」をマウントするタイプの違い
Nodejsアプリ開発を行う上で、今回のお題で言うとところの
かつては単にDockerでVolumeをマウントと言うと、暗黙的に「バインドマウント」のことを指していました。
Dockerも進化を遂げており現在はDockerコンテナから扱うデータの「マウントタイプ」と呼ばれるいくつかの方式が存在しています。
Dockerでデータを扱う4つのマウントタイプ
公式のリファレンスでも詳しく記述されてあるように、Dockerのデータ管理・アクセスのメカニズムには4つの方式が選択できます。
Volume
Bind Mounts
tmpfs Mounts
Named Pipes
この内、
tmpfs Mounts
Named Pipes
Volume
Bind Mounts
Dockerでの「Volume」と「Bind Mounts」の違い
元々、Dockerを使い慣れている方にはお馴染みの、ホスト側のファイルシステムをDockerコンテナ側へ共有させようとした際に使ってきた方式を「バインドマウント(Bind Mounts)」と呼んでいます。
公式の説明で利用されている模式図をそのまま引用しますと、
501x255

というイメージで構成されています。
まず「バインドマウント」を使うことで、ホスト上のファイル/フォルダ(つまりFilesystem)を、起動したDockerコンテナーにマウントすることでリソースをホスト間で共有できるようになります。
対して、Dockerは「ボリューム(Volume)」を別に作成することで、ホスト側のFilesystem内に「Docker area」を専有的に設けることが出来ます。
このDocker Areaでは、Dockerコンテナが独自に管理できて、かつホストなどの非Dockerプロセスからはアクセス出来ないように独立して切り離されたストレージとして使うことができます。
バインドマウントと違って、ホスト側からリソースを書き換えられることがないので、何らかのホスト側のプロセスが原因でうっかりファイルの内容が変更されたということもなくなり、高速かつ安全な処理がDocker側で可能になります。
また、この名前を付けたボリューム(
external: true
コンテナが停止した後もボリューム自体は永続化し、自動では削除されなくなり、各ボリュームの詳細は
docker volume ls
docker-composeにおけるマウントの記述法について
docker-compose.ymlのvolumesタグに関して、現在では2種類の書式があります。
まずは伝統的なワンライナーで記述する方法です。
書式:
[SOURCE:]TARGET[:MODE]
+ SOURCE: ホスト側であればコピー元のパス。
もしくは定義済みボリューム名
+ TARGET: ボリュームのマウント先となるコンテナ上のパス
+ MODE: (オプション)マウント後のファイル・フォルダの属性。
roで読み込み専用、rwで読み書き許可、など
docker-composeに慣れ親しんだ方だとおなじみのパターンですが、先述したマウントが増えてきたために、曖昧で紛らわしくなってきた経緯があります。
そこで、docker-composeのバージョン3.2以降で追加になったマウントタイプをより明確に書き出す記述法(通称・「長い書式」)の利用が推奨されています。
#...
services:
app:
#...
volumes:
#👇「ボリューム」タイプでマウント
- type: volume
source: my-data
target: /hoge
#👇バインドマウント
- type: bind
source: ./piyo
target: /app/piyo
volumes:
my-data:
こうすることで、バインドマウントなのかボリュームなのか明瞭に理解することができます。
「長い書式」で追加になったパラメータが多少増えていますので、詳しくは公式のドキュメントを参照のこと。
Dockerコンテナにマウントする際に特定のファイル・フォルダを除外する
前置きはさておき、本題のDockerコンテナからファイル・フォルダをマウント時に除外する方法をやってみましょう。
とりあえず現在のホスト側の作業フォルダ
./
app
#...
services:
app:
#...
volumes:
- .:/app
当たり前ですが、Dockerコンテナ側から見るとすべてのリソース見えるし、ホスト側からファイル書き込みしたらDockerコンテナ側からもその変更が反映されます。
マウントからファイルを除外する
ファイルの除外は
/dev/null
#...
services:
app:
#...
volumes:
- .:/app
#hoge.txtは除外
- /dev/null:/app/hoge.txt
これで作業フォルダにあった
hoge.txt
マウントからフォルダを除外する
ファイルだけでなく今度はフォルダごっそり除外させてみましょう。
除外のパターンは2つあり、通常割と紹介されているのが「バインドマウント」的なやり方です。
#...
services:
app:
#...
volumes:
- .:/app
#node_modulesは除外
- /app/node_modules/
考え方としては、先にホスト側の作業ディレクトリの中身がすべてコンテナ側の
app
node_modules
「<名無しのボリューム>:/app/node_modules/」
この名無しのボリュームはどこにも定義されておらず、いわば実態のない空のボリュームということで、ここにマウントされたフォルダはすべてコンテナ側からは除外されます。
このやり方ではDocker側からアクセスできるデータではなくなってしまうので、データを複数のDockerコンテナ間で共有させる必要がある場合、バインドマウントではなく、「定義済みボリューム」を作成してからそこにマウントするといいでしょう。
#...
services:
app:
#...
volumes:
- .:/app
- hoge:/app/node_modules/
volumes:
hoge:
こちらのやり方では、
node_modules
hoge
まとめ
今回はDockerコンテナへホスト側からファイルやフォルダをコピーする際に知っておきたい、include/excludeの指定方法について簡単に説明しました。
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー