バインドマウントもボリュームと同じくコンテナのデータをホストマシンと共有する方法です。
このページではバインドマウントの使い方とボリュームとの使い分けについて学びます。
全体構成とハイライト
やることの確認
\ | やること | できるようになること |
---|---|---|
App | イメージをビルド | ✅ PHP が準備できる ✅ メール送信が準備できる |
App | コンテナを起動しビルド結果を確認 Web サーバを起動 |
✅ Dockerfile の妥当性が確認できる ✅ Web サーバが起動できる |
App | 👉 ソースコードをバインドマウント | ホストマシンの .php 編集が即反映される |
App | コンテナのポートを公開 | ブラウザからアクセスできる |
App | コンテナをネットワークに接続 データベースサーバの接続設定 メールサーバの接続設定 |
DB コンテナに接続できる Mail コンテナに接続できる |
App | Docker Compose 化 | これらを1コマンドで再現できる |
DB | イメージをビルド | ✅ 文字コードとログの設定ができる |
DB | 環境変数を指定してコンテナを起動 | ✅ Dockerfile の妥当性が確認できる ✅ MySQL サーバが起動できる ✅ ユーザとデータベースを作成できる |
DB | データ置場にボリュームをマウント | ✅ テーブルがコンテナ削除で消えなくなる |
DB | 👉 初期化クエリをバインドマウント | コンテナ起動時にテーブルが作成される |
DB | コンテナをネットワークに接続 コンテナにエイリアスを設定 |
App コンテナからホスト名で接続できる |
DB | Docker Compose 化 | これらを1コマンドで再現できる |
イメージを選定 | ✅ SMTP サーバが起動できる ✅ Web サーバが起動できる |
|
コンテナを起動 | ✅ Web サーバが起動できる ✅ SMTP サーバが起動できる |
|
コンテナのポートを公開 | ブラウザからアクセスできる | |
コンテナをネットワークに接続 コンテナにエイリアスを設定 |
App コンテナからホスト名で接続できる | |
Docker Compose 化 | これらを1コマンドで再現できる | |
ほか | ボリュームを作成 | ✅ マウントする準備ができる |
ほか | ネットワークを作成 | コンテナを接続する準備ができる |
バインドマウントとは
バインドマウントは ホストマシンの任意のディレクトリをコンテナにマウントする 仕組みです。
ホストマシンとコンテナ双方がファイルの変更に関心がある という場合に有用で、たとえばソースコードの共有などに活用できます。
ソースコードのディレクトリをコンテナにバインドマウントしてホストマシン側と共有すれば、ホストマシンでコードを変更した際に同期や転送が不要 になります。
構築
App コンテナに .php
をバインドマウントして、ホストマシンで PHP のコーディングをする準備を整えます。
App コンテナにソースコードをマウントする
バインドマウントはボリュームと違い 既存のディレクトリをそのままマウントする ので、事前作成などはありません。
バインドマウントも --volume
オプションと --mount
オプションどちらでも行えます。
【 3部: ボリューム 】で --mount
オプションを使う方が良いと結論づけましたが、せっかくなので両方説明します。
--volume オプションによるマウント
バインドマウントを行う場合も、:
区切りで設定を列挙します。
1つめを ボリューム名ではなく絶対パスにする とバインドマウントと判断されます。値はソースコードのある $(pwd)/src
を指定します。
2つめはマウント先であり、これは自分で都合の良い場所にします。今回は /src
とします。
3つめのオプションは特に指定しません。
また、ビルトインウェブサーバーのドキュメントルートをソースコードをマウントして配置する /src
に変更したいため、<command>
の末尾に -t /src
を付け加えます。
$ docker container run \
--name app \
--rm \
--detach \
--interactive \
--tty \
--volume $(pwd)/src:/src \
docker-practice:app \
php -S 0.0.0.0:8000 -t /src
--mount オプションによるマウント
バインドマウントを行う場合も、同じキーを使って key=value
方式で設定します。
type
は volume
ではなく bind
を指定します。
source
はソースコードのある $(pwd)/src
を指定します。
destination
は /src
を指定します。
$ docker container run \
--name app \
--rm \
--detach \
--interactive \
--tty \
--mount type=bind,src=$(pwd)/src,dst=/src \
docker-practice:app \
php -S 0.0.0.0:8000 -t /src
ソースコードがマウントできたことを確認する
App コンテナに接続して /src
ディレクトリが確認できれば大丈夫です。
$ docker container exec \
--interactive \
--tty \
app \
bash
# ls /src
form.php history.php index.php mail.php
ホストマシンの変更がコンテナ内に、コンテナ内の変更がホストマシンに、即時反映されることが確認できます。
$ echo 'Hello World' > src/hello.txt
# cat /src/hello.txt
Hello World
# rm /src/hello.txt
$ ls src
form.php history.php index.php mail.php
ドキュメントルートを変更したので、Web サーバの応答を確認しておきます。
# curl -sS localhost:8000 | grep '<title>'
<title>Hello | Docker Practice</title>
ホストマシンに置いた index.php
を使ったレスポンスが得られれば大丈夫です。
DB コンテナに初期化クエリをマウントする
mysql:5.7
イメージは、コンテナ起動時に /docker-entrypoint-initdb.d
に存在する .sql
を実行してくれる拡張がされています。
そこに create table
文をバインドマウントしてコンテナを起動すれば、【 3部: コンテナの起動 】で環境変数で作ったデータベースとユーザに加えてテーブルも初期化することができます。
まずは実行したい .sql
を作成します。
ルールはありませんが Dockerfile の近くが妥当でしょう。
create table event.mail
(
sent_to varchar(32) not null,
subject varchar(32) not null,
body varchar(64) not null,
sent_at varchar(32) not null,
result char(1) not null
);
これを --mount
オプションでバインドマウントして DB コンテナを起動します。
ただし初期化クエリは既にデータが存在する場合は実行されないため、docker-practice-db-volume
の削除と再作成をする必要があります。
【 3部: ボリューム 】の最後で再作成をしていない方は確認してください。
まっさらなボリュームのマウントと初期化クエリのバインドマウントの2つを指定して、次のようにコンテナを起動します。
$ docker container run \
--name db \
--rm \
--detach \
--platform linux/amd64 \
--env MYSQL_ROOT_PASSWORD=rootpassword \
--env MYSQL_USER=hoge \
--env MYSQL_PASSWORD=password \
--env MYSQL_DATABASE=event \
--mount type=volume,src=docker-practice-db-volume,dst=/var/lib/mysql \
--mount type=bind,src=$(pwd)/docker/db/init.sql,dst=/docker-entrypoint-initdb.d/init.sql \
docker-practice:db
初期化クエリが実行されたことを確認する
DB コンテナに接続して event.mail
テーブルがあることを確認できれば大丈夫です。
$ docker container exec \
--interactive \
--tty \
db \
mysql -h localhost -u hoge -ppassword event
mysql> show tables;
+-----------------+
| Tables_in_event |
+-----------------+
| mail |
+-----------------+
バインドマウントの実体と注意
バインドマウントの実体は そのままホストマシンのファイルシステム です。
つまりバインドマウントはボリュームと比べると 実体の面倒を見ているのが Docker ではなく自分 であり、それが ホストマシン上 であるという違いがあります。
「仮想環境だから」と安易に rm -rf *
でもして、もしそこにバインドマウントしたディレクトリが含まれていたら、削除はホストマシンに波及します。
Git を使っていれば事故があってもなんとかなりますし、そもそも /
を /
にマウントするような極端なことをしなければ危険は全然ありませんが、違いは正しく把握しておくと良いでしょう。
Docker の公式も まずはボリュームを検討し、どうしてもだめならバインドマウントを使え と言っています。
COPY とバインドマウントの使い分け
COPY
とバインドマウントはどちらもホストマシンのファイルをコンテナで扱えるようにする機能ですが、用途 と 反映タイミング を理解しておかないと扱いを間違えやすいので整理しましょう。
COPY
は image build
をするタイミングでイメージにファイルを含める ため、コンテナが起動すればファイルが存在 します。
また 元ファイルの変更を行ってもコンテナには反映されない ため、image build
の再実行が必要 になります。
COPY
の用途には次のようなものが挙げられるでしょう。
- 設定ファイルなど、コンテナによって変えない かつ 滅多に変更しない ものを配置する場合
- 本番デプロイ時のソースコードなど、即起動できる配布物を作る 場合
対してバインドマウントは イメージではなくコンテナに行う ため、同じイメージを使ってもファイルの存在はコンテナ起動のオプションによって異なります。
また ホストマシンでファイルを変更するとコンテナに即時影響します。
バインドマウントの用途には次のようなものが挙げられるでしょう。
- 開発時のソースコードなど、ホストマシンで変更したいがコンテナに随時反映したい ものがある場合
- 初期化クエリなど、イメージを配布する時点では用意できない ものがある場合
2つは イメージに対して行っている か コンテナに対して行っている かが明確に違います。
その点をちゃんと理解しておけば、使い分け も 変更したいならどうすべきか も判断できます。
まとめ
このページの手順書と成果物は次のディレクトリで公開されています。
混乱してしまったときに参考にしてください。
ポイント
- バインドマウントは ホストマシンでもファイルに関心がある という用途に向いている
- コンテナ内でのファイル削除などが ホストマシンに影響する 可能性がある
-
イメージに対して行う
COPY
とは コンテナに対して行う 点が大きく違う
できるようになったことの確認
\ | やること | できるようになること |
---|---|---|
App | イメージをビルド | ✅ PHP が準備できる ✅ メール送信が準備できる |
App | コンテナを起動しビルド結果を確認 Web サーバを起動 |
✅ Dockerfile の妥当性が確認できる ✅ Web サーバが起動できる |
App | 👉 ソースコードをバインドマウント | ✅ ホストマシンの .php 編集が即反映される |
App | コンテナのポートを公開 | ブラウザからアクセスできる |
App | コンテナをネットワークに接続 データベースサーバの接続設定 メールサーバの接続設定 |
DB コンテナに接続できる Mail コンテナに接続できる |
App | Docker Compose 化 | これらを1コマンドで再現できる |
DB | イメージをビルド | ✅ 文字コードとログの設定ができる |
DB | 環境変数を指定してコンテナを起動 | ✅ Dockerfile の妥当性が確認できる ✅ MySQL サーバが起動できる ✅ ユーザとデータベースを作成できる |
DB | データ置場にボリュームをマウント | ✅ テーブルがコンテナ削除で消えなくなる |
DB | 👉 初期化クエリをバインドマウント | ✅ コンテナ起動時にテーブルが作成される |
DB | コンテナをネットワークに接続 コンテナにエイリアスを設定 |
App コンテナからホスト名で接続できる |
DB | Docker Compose 化 | これらを1コマンドで再現できる |
イメージを選定 | ✅ SMTP サーバが起動できる ✅ Web サーバが起動できる |
|
コンテナを起動 | ✅ Web サーバが起動できる ✅ SMTP サーバが起動できる |
|
コンテナのポートを公開 | ブラウザからアクセスできる | |
コンテナをネットワークに接続 コンテナにエイリアスを設定 |
App コンテナからホスト名で接続できる | |
Docker Compose 化 | これらを1コマンドで再現できる | |
ほか | ボリュームを作成 | ✅ マウントする準備ができる |
ほか | ネットワークを作成 | コンテナを接続する準備ができる |
次のページに進む前に
起動オプションをどんどん増やしていくため、このページで起動したコンテナは終了します。
$ docker container rm --force \
app db
中途半端にボリュームにデータが残っているとこの先の【 3部: Docker Compose 】で都合が悪いので、ボリュームを削除しておきます。
$ docker volume rm \
docker-practice-db-volume