⛓️

【初学者向け】Dockerバインドマウントの基礎と実践

2024/06/02に公開

はじめに

この記事では、Dockerのバインドマウントについて説明します。

私の動作環境

  • Docker Desktop 4.30.0 (149282)
  • Docker Engine 26.1.1
  • Docker Compose v2.27.0-desktop.2
  • MacOS Sonoma 14.5

Dockerコマンド一覧

Dockerのコマンド一覧は、以下のサイトに記載されています。このサイトは、Docker公式ドキュメントを有志の方々が日本語に翻訳してくれているものです。

https://docs.docker.jp/engine/reference/commandline/index.html

公式による最新のドキュメントを確認したい人は、以下のリンクから飛ぶことができます。

https://docs.docker.com/

バインドマウントって何?

Dockerのバインドマウントは、コンテナとホストシステムのファイルシステムを共有するための機能です。これにより、ホスト上の特定のディレクトリやファイルをコンテナ内にマウントすることができます。

バインドマウントを使用すると、ホストマシン上のディレクトリをコンテナ内のディレクトリにリンクさせることができます。

Dockerコンテナとファイルの独立性

バインドマウントを行う前に、Dockerコンテナとファイルの独立性について理解しておくことが大切です。
Dockerコンテナは、それぞれが隔離された実行環境です。コンテナを破棄した場合、その中にあるファイルは失われます。いくつ起動しても、それらが互いに影響を受けることはありません。

2つのコンテナを作成してみる

ここでhttpdイメージを利用し、2つのコンテナを作成してみます。httpdの使い方などは以下のサイトを確認してください。

https://hub.docker.com/_/httpd

コンテナの名前はそれぞれweb01とweb02とします。web01はポート8080、web02はポート8081にマッピングすることにします。また、どちらもオプションを指定せず、マウントを行わないようにすると、この2つのコンテナは完全に互いに独立します。

docker run -dit --name web01 -p 8080:80 httpd:2.4


一つ目のコンテナ作成

docker run -dit --name web02 -p 8081:80 httpd:2.4


二つ目のコンテナ作成

docker psコマンドで確認すると、どちらのコンテナも実行中であることが確認できました。

これでApacheが実際に2つ起動しているはずです。ブラウザから「http://Dockerホスト:8080/」および「http://Dockerホスト:8081/」に接続して確認すると、どちらにも接続でき「It works!」と表示されました。


http://Dockerホスト:8080/に接続した場合

このようにして、1台のDockerホストに2台のWebサーバーを同居させることができました。

コンテナ内にファイルをコピーする

先ほど2つのコンテナを作成しましたが、どちらもまだコンテンツファイルを置いていないので両方とも「It works!」と表示され区別が付きません。そこでindex.htmlファイルを置いて、片方を「It's web01!」、もう片方を「It's web02!」と表示できるようにしてみます。

ここで、コンテナとローカルファイルシステム間でファイルやフォルダをコピーできるdocker cpコマンドというものが存在します。これを用いて、index.htmlをDockerホストに作成し、それをコンテナにコピーすることで表示を変更できるようにしてみます。

1./tmpディレクトリにindex.htmlを作成する

まずはindex.htmlファイルを/tmpディレクトリ内に作成します。
ここで/tmpディレクトリにカレントディレクトリを移動する際に、後で現在のカレントディレクトリに戻れるように、pushdコマンドを使ってディレクトリを移動することにします。

pushd /tmp

これによって、/tmpディレクトリに移動できました。

ここから、web01コンテナ用のindex.htmlファイルをnanoエディタなどで作成して用意します。

nano index.html

また、index.htmlの中身は以下のようにし、「It's web01!」と表示するようにします。

index.html
<html>
<body>
<div>It's web01!</div>
</body>
<html>

2.ファイルをコンテナにコピーする

このindex.htmlをコンテナweb01の/usr/local/apache2/htdocs/にコピーするために、次のように実行してみます。

docker cp /tmp/index.html web01:/usr/local/apache2/htdocs/


「Sucessfully」と出ていることから、コピーが成功していることが確認できる

3.ブラウザで確認してみる

ブラウザでhttp://Dockerホスト:8080/に接続すると、コピーしたindex.htmlの内容である「It's web01!」の表示が確認できました。

4.コンテナの内部に入って確認してみる

本当にdocker cpコマンドでindex.htmlの内容がコピーされているのか、コンテナの内部に入って確認してみます。
実行中のコンテナの中を操作するにはdocker execコマンドを使えば良いので、それを用いてweb01コンテナの内部に入ってみます。

docker exec -it web01 /bin/bash

コンテナの内部に入ってcatコマンドでindex.htmlの内容を確認すると、docker cpコマンドでコピーした内容と一致していることが確認できました。

確認が終わったので、exitでコンテナの外に出ます。

5.web02も同様に行う

コンテナweb02に関しても同様に確認してみます。まず、/tmpディレクトリにindex02.htmlとして以下の内容を保存します。

index02.html
<html>
<body>
<div>It's web02!</div>
</body>
<html>

このindex02.htmlという名前のファイルをコンテナにindex.htmlとしてコピーします。

docker cp /tmp/index02.html web02:/usr/local/apache2/htdocs/index.html


「Sucessfully」と出ていることから、コピーが成功していることが確認できる

ブラウザでhttp://Dockerホスト:8081/に接続すると、コピーしたindex02.htmlの内容である「It's web02!」の表示が確認できました。

6.カレントディレクトリを戻す

pushdコマンドを使ってディレクトリを移動しているので、以下のコマンドで元のディレクトリに戻ります。

popd

コンテナを作り直してファイルの中身を確認する

先ほどの作業を完了させた段階でコンテナの状態を確認すると、web01とweb02の二つのコンテナが存在していることがわかります。

1.コンテナの停止

ここでdocker stopでweb01を停止させると、ブラウザでhttp://Dockerホスト:8080/に接続できなくなります。

2.コンテナの再稼働

また、docker startでweb01を再稼働させると、ブラウザでhttp://Dockerホスト:8080/に接続できるようになります。


接続できるように

3.コンテナの破棄

ここで、コンテナを破棄してみます。docker stopでweb01を停止させ、docker rmで削除します。

確認すると、コンテナは完全に削除されていました。


web01が存在していない様子

4.コンテナの再構築

破棄したweb01コンテナを作り直してみます。以下のコマンドを実行し、その後docker psで確認します。

docker run -dit --name web01 -p 8080:80 httpd:2.4

この状態でブラウザからhttp://Dockerホスト:8080/に接続すると、「It's web01!」と表示されるのではなく「It works!」と表示されました。

5.コンテナの内部に入って確認してみる

web01コンテナの内部に入って、catコマンドでindex.htmlの内容を確認すると「It works!」となっていることがわかります。

このように、同じ名前でコンテナを起動し直したとしても中身の内容は失われるということがわかります。
コンテナの破棄は慎重に行う必要があるということですね。

実際にバインドマウントをやってみた

docker rmでコンテナを破棄すると、そのコンテナの中にあるデータは失われます。しかし、コンテナで失いたくないデータをコンテナの外に出すことができればその問題は解決します。

そのような場合に役に立つのがマウントです。マウントを行うことでコンテナが削除されてもデータは失われず、永続化することができます。
この記事では、バインドマウントを行います。

1.コンテナの停止と破棄

先ほどの作業の続きからバインドマウントをしていきます。

まず、web01コンテナを停止して破棄します。

2.マウントするディレクトリの作成をする

私は、/Users/[私の名前]ディレクトリに「web01data」というディレクトリを作成しました。

mkdir web01data


web01dataディレクトリの作成

また、Dockerがホストシステムのディレクトリにアクセスできるようにするためには、ホストシステム上のディレクトリをDocker Desktopの設定で共有パスとして追加する必要があります。

Docker Desktopの設定を開き、「Settings」を選択します。

そこからFile Sharingに移動し、「+」ボタンをクリックして新しいディレクトリを追加します。

この手順を完了することで、Dockerは/Users/[私の名前]/web01dataディレクトリにアクセスし、コンテナにマウントできるようになります。

3.index.htmlを作成する

web0data内に以下のような内容のindex.htmlを配置します。

index.html
<html>
<body>
<div>mount test</div>
</body>
<html>

4.ディレクトリをバインドマウントしてweb01コンテナを起動する

「web01data」ディレクトリを/usr/local/apache2/htdocsにマウントしてweb01コンテナを起動します。

docker run -dit --name web01 -v /Users/[私の名前]/web01data:/usr/local/apache2/htdocs -p 8080:80 httpd:2.4

docker psで確認すると、無事にコンテナが起動していることがわかります。

5.ブラウザで確認してみる

この状態でブラウザからhttp://Dockerホスト:8080/に接続すると、「mount test」と表示されました。

また、このコンテナを破棄して作り直してもindex.htmlは失われず、同じように表示されます。

このようにマウントすることで、データの永続性を確保しつつ、コンテナの利便性や移植性を保つことができます。

バインドマウントの利点

ここまでの例では、コンテナ側からマウントしたファイルを書き換えませんでしたが、もちろん書き換えることもできます。書き換えた場合、そのデータはそのまま残ります。このようにバインドマウントを使用することでデータは失われません。間違えてdocker rmで破棄しても影響を受けません。これはコンテナのアップデートや差し替えが容易になることを意味します。

また、マウントの手法は、データを失わないようにするだけでなく、コンテナ間でのデータ共有にも利用できます。1つの場所を2つ以上のコンテナで同時にマウントすることで、コンテナ間でファイルを共有できます。

Dockerでは、コンテナ内の設定ファイルを書き換えるために特定のフォルダやファイルをマウントすることもあります。例えば、httpdコンテナでは/usr/local/apache2/confディレクトリにApacheの設定ファイルがあり、設定を変更したいときはこのファイルを書き換えます。マウントを使用すれば、Dockerホスト上の適当なディレクトリに同じ内容のものを用意し、そのファイルを書き換えた上でdocker runする際にマウントするといったことが可能になります。
この方法なら、Dockerホストに設定ファイルが残るので、設定のバックアップが容易です。

さいごに

ざっくりまとめてみます。

1. コンテナを破棄するとデータも破棄される
コンテナは隔離された実行環境にすぎません。docker rmでコンテナを削除すると、データは失われます。

2. データを永続化したい場合はマウントすると良い
コンテナを破棄してもデータを残したい場合は、保存先をDockerホストのディレクトリなどの外に出してマウントすることで、失われないようにします。

3. バインドマウント
バインドマウントとは、Dockerホストのディレクトリをマウントする方法です。

ここまで記事を読んでくださり、ありがとうございました!今回は、私がDockerを利用していく中で重要だと感じたバインドマウントについてまとめてみました。

今後も、Dockerを理解するために突き進んでいきたいと思います!

皆さんも素敵なハッピーDockerライフを!!!🌸

GitHubで編集を提案

Discussion