前書き
Dockerは、実行に必要なすべてを含むファイルシステムをソフトウェアアプリケーションに提供するために使用される一般的なコンテナ化ツールです。 Dockerコンテナーを使用すると、実行時環境が一貫しているため、ソフトウェアが展開先に関係なく同じように動作します。
一般に、Dockerコンテナーは一時的なものであり、コンテナーで発行されたコマンドが完了するのに必要な時間だけ実行されます。 ただし、コンテナが削除された後、アプリケーションがデータへのアクセスを共有したり、データを保持したりする必要がある場合があります。 データベース、Webサイトのユーザー生成コンテンツ、およびログファイルは、Dockerイメージに含めることは非現実的または不可能であるが、アプリケーションがアクセスする必要があるデータのほんの一例です。 データへの永続的なアクセスはDocker Volumesで提供されます。
Dockerボリュームは、コンテナを作成するのと同じコマンドで作成およびアタッチできます。または、コンテナとは独立して作成し、後でアタッチできます。 この記事では、コンテナ間でデータを共有する4つの異なる方法について説明します。
前提条件
この記事を読むには、次のものを備えたUbuntu 18.04サーバーが必要です。
-
sudo特権を持つ非rootユーザー。 Initial Server Setup with Ubuntu 18.04ガイドでは、これを設定する方法について説明しています。
-
How To Install and Use Docker on Ubuntu 18.04のStep 1およびStep 2からの指示とともにインストールされたDocker
[.note]#Note:前提条件にUbuntu 18.04にDockerをインストールする手順が記載されていますが、この記事のDockerデータボリュームのdocker
コマンドは、Dockerがインストールされている限り他のオペレーティングシステムでも機能するはずです。 sudoユーザーがdocker
グループに追加されました。
#
[[step-1 -—- creating-an-independent-volume]] ==ステップ1—独立したボリュームの作成
Dockerの1.9リリースで導入されたdocker volume create
コマンドを使用すると、特定のコンテナーに関連付けずにボリュームを作成できます。 このコマンドを使用して、DataVolume1
という名前のボリュームを追加します。
docker volume create --name DataVolume1
コマンドが成功したことを示す名前が表示されます。
OutputDataVolume1
ボリュームを利用するために、Ubuntuイメージから新しいコンテナを作成し、--rm
フラグを使用して、終了時に自動的に削除します。 また、-v
を使用して新しいボリュームをマウントします。 -v
には、ボリュームの名前、コロン、およびコンテナー内でボリュームが表示される場所への絶対パスが必要です。 パス内のディレクトリが画像の一部として存在しない場合、コマンドの実行時に作成されます。 それらがdo存在する場合、マウントされたボリュームは既存のコンテンツを非表示にします。
docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu
コンテナにいる間に、いくつかのデータをボリュームに書き込みましょう。
echo "Example1" > /datavolume1/Example1.txt
--rm
フラグを使用したため、終了時にコンテナは自動的に削除されます。 ただし、ボリュームは引き続きアクセス可能です。
exit
ボリュームがシステムに存在することをdocker volume inspect
で確認できます。
docker volume inspect DataVolume1
Output[
{
"CreatedAt": "2018-07-11T16:57:54Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/DataVolume1/_data",
"Name": "DataVolume1",
"Options": {},
"Scope": "local"
}
]
[.note]#Note:Mountpoint
としてリストされているパスにあるホスト上のデータを確認することもできます。 ただし、アプリケーションやコンテナが変更を認識していない場合、データが破損する可能性があるため、変更は避けてください。
#
次に、新しいコンテナを起動して、DataVolume1
をアタッチします。
docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu
内容を確認します。
cat /datavolume1/Example1.txt
OutputExample1
コンテナを終了します。
exit
この例では、ボリュームを作成し、コンテナに接続して、その永続性を検証しました。
[[ステップ-2 -—-コンテナが削除されたときに永続するボリュームの作成]] ==ステップ2—コンテナが削除されたときに永続するボリュームの作成
次の例では、コンテナと同時にボリュームを作成し、コンテナを削除してから、ボリュームを新しいコンテナにアタッチします。
docker run
コマンドを使用して、ベースのUbuntuイメージを使用して新しいコンテナーを作成します。 -t
は端末を提供し、-i
はそれと対話できるようにします。 わかりやすくするために、--name
を使用してコンテナを識別します。
-v
フラグを使用すると、新しいボリュームを作成できます。これをDataVolume2
と呼びます。 コロンを使用して、ボリュームをコンテナにマウントするパスからこの名前を分離します。 最後に、ベースのUbuntuイメージを指定し、Ubuntu base image’s Docker file、bash
のデフォルトコマンドを使用して、シェルにドロップします。
docker run -ti --name=Container2 -v DataVolume2:/datavolume2 ubuntu
[。注意]##
Note:-v
フラグは非常に柔軟です。 構文をわずかに調整するだけで、ボリュームをバインドマウントしたり、ボリュームに名前を付けたりできます。 最初の引数が/
または~/
で始まる場合は、バインドマウントを作成しています。 それを削除すると、ボリュームに名前が付けられます。 例えば:
-
-v /path:/path/in/container
はホストディレクトリをマウントし、/path
は/path/in/container
にマウントします -
-v path:/path/in/container
は、ホストとは関係のないpath
という名前のボリュームを作成します。
ホストからのディレクトリのバインドマウントの詳細については、How To Share Data between a Docker Container and the Host
を参照してください。
コンテナ内で、ボリュームにいくつかのデータを書き込みます。
echo "Example2" > /datavolume2/Example2.txt
cat /datavolume2/Example2.txt
OutputExample2
コンテナを終了しましょう:
exit
コンテナを再起動すると、ボリュームが自動的にマウントされます。
docker start -ai Container2
ボリュームが実際にマウントされ、データがまだ存在していることを確認しましょう。
cat /datavolume2/Example2.txt
OutputExample2
最後に、終了してクリーンアップしましょう。
exit
Dockerでは、コンテナから参照されているボリュームを削除できません。 試してみるとどうなるか見てみましょう:
docker volume rm DataVolume2
このメッセージは、ボリュームがまだ使用中であり、コンテナIDの長いバージョンを提供していることを示しています。
OutputError response from daemon: unable to remove volume: remove DataVolume2: volume is in use - [d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63]
このIDを使用して、コンテナを削除できます。
docker rm d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63
Outputd0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63
コンテナを取り外してもボリュームには影響しません。 ボリュームをdocker volume ls
で一覧表示すると、システムにまだ存在していることがわかります。
docker volume ls
OutputDRIVER VOLUME NAME
local DataVolume2
そして、docker volume rm
を使用してそれを削除できます。
docker volume rm DataVolume2
この例では、コンテナを作成すると同時に空のデータボリュームを作成しました。 次の例では、既にデータが含まれているコンテナディレクトリでボリュームを作成するとどうなるかを見ていきます。
[[step-3 -—- creating-a-volume-from-an-existing-directory-with-data]] ==ステップ3—既存のディレクトリからデータを使用してボリュームを作成する
一般に、docker volume create
を使用してボリュームを個別に作成することと、コンテナーの作成中にボリュームを作成することは、1つの例外を除いて同等です。 コンテナandを作成すると同時にボリュームを作成する場合、ベースイメージにデータを含むディレクトリへのパスを指定すると、そのデータがボリュームにコピーされます。
例として、コンテナを作成し、ベースイメージのデータを含むディレクトリである/var
にデータボリュームを追加します。
docker run -ti --rm -v DataVolume3:/var ubuntu
ベースイメージの/var
ディレクトリのすべてのコンテンツがボリュームにコピーされ、そのボリュームを新しいコンテナにマウントできます。
現在のコンテナを終了します。
exit
今回は、ベースイメージのデフォルトのbash
コマンドに依存するのではなく、独自のls
コマンドを発行します。これにより、シェルに入らずにボリュームの内容が表示されます。
docker run --rm -v DataVolume3:/datavolume3 ubuntu ls datavolume3
ディレクトリdatavolume3
には、ベースイメージの/var
ディレクトリの内容のコピーが含まれるようになりました。
Outputbackups
cache
lib
local
lock
log
mail
opt
run
spool
tmp
この方法で/var/
をマウントする可能性は低いですが、独自のイメージを作成し、データを簡単に保存する方法が必要な場合は、これが役立ちます。 次の例では、複数のコンテナ間でボリュームを共有する方法を示します。
[[step-4 -—- sharing-data-between-multiple-docker-containers]] ==ステップ4—複数のDockerコンテナ間でデータを共有する
これまでのところ、一度に1つのコンテナーにボリュームをアタッチしました。 多くの場合、同じデータボリュームに複数のコンテナを接続する必要があります。 これを達成するのは比較的簡単ですが、1つの重要な注意事項があります。現時点では、Dockerはファイルのロックを処理しません。 ボリュームへの複数のコンテナーの書き込みが必要な場合、それらのコンテナーmustで実行されているアプリケーションは、データの破損を防ぐために共有データストアに書き込むように設計されています。
Container4およびDataVolume4を作成します
docker run
を使用して、データボリュームがアタッチされたContainer4
という名前の新しいコンテナを作成します。
docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu
次に、ファイルを作成してテキストを追加します。
echo "This file is shared between containers" > /datavolume4/Example4.txt
次に、コンテナを終了します。
exit
これにより、ホストコマンドプロンプトに戻ります。ここで、Container4
からデータボリュームをマウントする新しいコンテナを作成します。
Container5を作成し、Container4からボリュームをマウントする
Container5
を作成し、Container4
からボリュームをマウントします。
docker run -ti --name=Container5 --volumes-from Container4 ubuntu
データの永続性を確認しましょう。
cat /datavolume4/Example4.txt
OutputThis file is shared between containers
次に、Container5
からいくつかのテキストを追加しましょう。
echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt
最後に、コンテナを終了します。
exit
次に、データがContainer4
にまだ存在することを確認します。
Container5で行われた変更を表示する
Container4
を再起動して、Container5
によってデータボリュームに書き込まれた変更を確認しましょう。
docker start -ai Container4
変更を確認します。
cat /datavolume4/Example4.txt
OutputThis file is shared between containers
Both containers can write to DataVolume4
両方のコンテナがデータボリュームから読み書きできることを確認したので、コンテナを終了します。
exit
繰り返しになりますが、Dockerはファイルロックを処理しないため、アプリケーションmustはファイルロック自体を考慮します。 コンテナが:ro
を追加することで読み取り専用アクセスが必要な場合に、データの破損が誤って発生しないように、Dockerボリュームを読み取り専用としてマウントすることができます。 これがどのように機能するか見てみましょう。
Container 6を起動し、ボリュームを読み取り専用でマウントします
ボリュームをコンテナーにマウントしたら、通常のLinuxファイルシステムのようにボリュームをアンマウントするのではなく、必要に応じてマウントした新しいコンテナーを作成し、必要に応じて以前のコンテナーを削除できます。 ボリュームを読み取り専用にするために、コンテナー名の末尾に:ro
を追加します。
docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu
サンプルファイルを削除して、読み取り専用ステータスを確認します。
rm /datavolume4/Example4.txt
Outputrm: cannot remove '/datavolume4/Example4.txt': Read-only file system
最後に、コンテナを終了し、テストコンテナとボリュームをクリーンアップします。
exit
以上で、コンテナとボリュームをクリーンアップしましょう。
docker rm Container4 Container5 Container6
docker volume rm DataVolume4
この例では、データボリュームを使用して2つのコンテナ間でデータを共有する方法と、データボリュームを読み取り専用としてマウントする方法を示しました。
結論
このチュートリアルでは、コンテナを削除してもデータを保持できるデータボリュームを作成しました。 コンテナ間でデータボリュームを共有しましたが、データの破損を防ぐためにファイルロックを処理するようにアプリケーションを設計する必要があることに注意してください。 最後に、共有ボリュームを読み取り専用モードでマウントする方法を示しました。 コンテナとホストシステム間でのデータの共有について知りたい場合は、How To Share Data between the Docker Container and the Hostを参照してください。