CUBE SUGAR CONTAINER

技術系のこと書きます。

Docker: データボリュームとデータボリュームコンテナ

Docker を使っているとデータの永続化が問題になる。 例えばデータベースのアプリケーションを動作させるとして、どこにデータを残せばいいだろう。 通常のファイルシステム上に置いてしまうと、コンテナが終了すると使えなくなってしまう。 そんなときに便利なのが今回使うデータボリュームとデータボリュームコンテナのようだ。 これを使うと Docker ホスト上のファイルをコンテナでマウントできるようになる。

データボリューム

まず、データボリュームから使ってみる。 コンテナにデータボリュームを接続するには docker run コマンドに -v オプションをつける。 もちろん Dockerfile で指定することもできて、そのときは VOLUME 命令を使う。

例えばコンテナの /mydata にデータボリュームをマウントしてみよう。 イメージには CentOS7 を使った。

$ docker run --name datavolume1 -i -v /mydata -t centos:7 /bin/bash

コンテナ上で df コマンドを確認すると /mydata に /dev/sda1 がマウントされていることがわかる。

# df
Filesystem     1K-blocks    Used Available Use% Mounted on
none            19049892 2073860  15985308  12% /
tmpfs             510044       0    510044   0% /dev
tmpfs             510044       0    510044   0% /sys/fs/cgroup
/dev/sda1       19049892 2073860  15985308  12% /mydata
shm                65536       0     65536   0% /dev/shm

一旦 Docker ホストの操作に戻ろう。 マウントされたデータボリュームの情報は docker inspect コマンドで確認できる。 ここで得られるフォーマットは JSON なので jq コマンドを使って表示内容を絞ると分かりやすい。

$ docker inspect datavolume1 | jq ".[0].Mounts"
[
  {
    "Name": "da484ac1637f1f18a85648b7c129ca33006a18c73f319f36fea1e257afb66a16",
    "Source": "/mnt/sda1/var/lib/docker/volumes/da484ac1637f1f18a85648b7c129ca33006a18c73f319f36fea1e257afb66a16/_data",
    "Destination": "/mydata",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]

上記では Docker ホスト上の /mnt/sda1/var/lib/docker/volumes/... にあるファイルが Docker コンテナの /mydata にマウントされていることが読み取れる。

試しにコンテナ上で /mydata にファイルを作ってみよう。

# cd /mydata/
# touch helloworld.txt

そして Docker ホスト側で先ほど docker inspect で確認したディレクトリを確認してみる。 するとコンテナの中で作ったファイルがそのまま見えることがわかる。

$ sudo ls /mnt/sda1/var/lib/docker/volumes/da484ac1637f1f18a8564
8b7c129ca33006a18c73f319f36fea1e257afb66a16/_data
helloworld.txt

なお、コンテナを終了したり削除してもこのデータボリュームとして使われているディレクトリは削除されない点に注意が必要だ。

このデータボリュームに使われるディレクトリの場所は指定することもできる。 それには -v オプションで \<dir>:\<mount> というようにカンマで区切って左側にそのパスを指定する。

$ docker run --name datavolume2 -i -v /tmp/mydata:/mydata -t centos:7 /bin/bash

上記では Docker ホスト上の /tmp/mydata を Docker コンテナの /mydata としてマウントする、という意味になる。

先ほどと同じように docker inspect でデータボリュームの情報を確認してみよう。

$ docker inspect datavolume2 | jq ".[0].Mounts"
[
  {
    "Source": "/tmp/mydata",
    "Destination": "/mydata",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
  }
]

この内容を見ても Docker ホストの /tmp/mydata が Docker コンテナの /mydata にマウントされたことが読み取れる。

先ほどと同じように Docker コンテナ側でファイルを /mydata においてみよう。

# cd /mydata/
# touch helloworld.txt

Docker ホスト側でマウントされたディレクトリをみるとファイルができていることがわかる。

$ ls /tmp/mydata
helloworld.txt

データボリュームコンテナ

次はデータボリュームコンテナという機能を試してみよう。 先ほどのデータボリュームは Docker ホスト上のファイルを Docker コンテナでマウントする機能だった。 データボリュームコンテナは、データボリュームをマウントした Docker コンテナから、別のコンテナがそのデータボリュームを使えるようにする機能だ。

まずはデータボリュームを使われる側のコンテナを用意する。 先ほどと同じように -v オプションでデータボリュームを追加しておこう。 名前は volumecontainer1 にしておく。 データボリュームは /sharedvolume に追加する。

$ docker run -d --name volumecontainer1 -v /sharedvolume -t centos:7 /bin/bash

docker inspect コマンドでデータボリュームが追加されていることを確認する。

$ docker inspect volumecontainer1 | jq ".[0].Mounts"
[
  {
    "Name": "fab265e09aae405baab9e4e5c36d0c4b0b77e9208b6d93610001562cc81fb457",
    "Source": "/mnt/sda1/var/lib/docker/volumes/fab265e09aae405baab9e4e5c36d0c4b0b77e9208b6d93610001562cc81fb457/_data",
    "Destination": "/sharedvolume",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]

次にデータボリュームを使う側のコンテナを作る。 このときはオプションとして --volumes-from で先ほどのコンテナの名前を指定しよう。

$ docker run --name vcuser1 --volumes-from volumecontainer1 -i -t centos:7 /bin/bash

コンテナに入ると /sharedvolume ディレクトリができている。

# find / -name sharedvolume
/sharedvolume

df の結果をみても /sharedvolume に /dev/sda1 がマウントされていることがわかる。

# df -a | grep sharedvolume
/dev/sda1       19049892 2294828  15764340  13% /sharedvolume

ディレクトリの中にファイルを作ってみよう。

# cd /sharedvolume/
# touch helloworld.txt

データボリュームコンテナは複数のコンテナから共有できる。 そこで、もう一台「使う側」のコンテナを起動してみよう。

$ docker run --name vcuser2 --volumes-from volumecontainer1 -i -t centos:7 /bin/bash

新しく起動したコンテナで /sharedvolume ディレクトリの中身を見ると、先ほど作ったファイルが見えている。

# ls /sharedvolume/
helloworld.txt

まとめ

今回は Docker のデータボリュームとデータボリュームコンテナという機能について見てきた。 コンテナは基本的にステートレスに作るのがベストプラクティスみたいだけど、どうしてもステートフルに作らなきゃいけないものはある。 例えば自前でデータベースを用意する場合なんかはその代表で、そこではどうしてもデータの永続化について考えなきゃいけない。 そんなときは今回見てきたデータボリュームとデータボリュームコンテナを使うと便利そうだ。