理系学生日記

おまえはいつまで学生気分なのか

ぜんぜんわからない、俺たちは雰囲気で Docker の Volume を使っている

ぜんぜんわからない、俺たちは雰囲気で Docker を使っているシリーズ、volume です。

$ docker -v
Docker version 18.03.1-ce, build 9ee9f40

まず、Docker においてデータを扱う場合、その扱いとしては、大きく 3 つに分けられます。

  • bind mount
  • volume
  • tmpfs mount

f:id:kiririmode:20180608151341p:plain
Manage data in Docker | Docker Documentation より引用

bind mount は Docker ホストの任意のファイル・ディレクトリを Container 内にマウントする機能、volume は Docker が管理するデータ領域を Container 上にマウントする機能です。 tmpfs は Linux でしか使えないけど、データ領域をメモリ上に置く機能です。まぁ、tmpfs の名前そのまま。

tmpfs は別として、bind mount、volume の機能を使用する際のオプション指定は、昔ほとんど同じで docker run -v src:dst:ro みたいなかんじだったと思います。

今でもこのオプションは使えるんですが、最近はこれよりも docker run --mount とするのが推奨されています。まぁ昔から -v オプションは分かりづらかったもんな。

volume を使ってマウント

まず事前状態を確認しておきます。最初は volume は作成されていません。

$ docker volume ls
DRIVER              VOLUME NAME

ここから、volume を使ってマウントしてみます。

$ docker run --name ubuntu1 -it \
             --mount type=volume,src=vol,dst=/vol1 \
             ubuntu /bin/bash
root@e796842acc29:/# ls /vol1
root@e796842acc29:/#

ここでは --mount を使ってマウントしていますが、このように --mount オプションはカンマ区切りでオプションを指定していきます。

これが読みやすいかどうかは個人の感覚に依りますが、ぼくは -v を使って「これって bind mount?それとも volume??」と混乱するよりは明示的で良いかなと思っています。

きちんと /vol1 が見えているようですね。ここでは、適当にファイルを作成しておきます。

root@e796842acc29:/# echo 'hello world!' > /vol1/hello.txt
  Ctrl-P Ctrl-Q

別コンテナで同じ volume をマウント

別コンテナで同じ volume をマウントしてみます。 きちんと、先程のファイルの内容が読み取れることが分かります。

$ docker run --name centos1 
             --mount type=volume,src=vol,dst=/vol-centos 
             -it centos /bin/bash
[root@acbe617deee3 /]# cat /vol-centos/hello.txt
hello world!

では、次にこの状態 (ubuntu1 と centos1 が同時に vol をマウントしている状態) で、centos1 が同じファイルに追記してみます。

[root@acbe617deee3 /]# date +%Y-%m-%d >> /vol-centos/hello.txt
Ctrl-P Ctrl-Q
$ docker exec ubuntu1 cat /vol1/hello.txt   # on Docker Host 
hello world!
2018-06-08

当然ですが、別コンテナでも同じファイルコンテンツを読み取ることができます。

ファイルが既に存在するディレクトリに volume をマウントしたら?

じゃぁ、ファイルが既に存在するディレクトリに volume をマウントしたらどうなるんかいな。

これはちょっと面白くて、「新規ボリューム」をマウントすると、何も起こりません。以下の例では、元々の /tmp に配置されているファイルがそのまま残ります。

$ docker run --rm --mount type=volume,src=hoge,dst=/tmp centos ls -l /tmp
total 4
-rwx------ 1 root root 836 May 31 18:03 ks-script-3QMvMi
-rw------- 1 root root   0 May 31 18:01 yum.log

一方で、ファイルが既に存在するディレクトリに「ファイルが既に存在するボリューム」をマウントすると、元々の /tmp にあったファイルが見えなくなります。 通常の mount っぽい挙動だ。

$ docker run --rm \
             --mount type=volume,src=vol,dst=/tmp 
             centos ls -l /tmp
total 4
-rw-r--r-- 1 root root 24 Jun  8 06:32 hello.txt

--volumes-from で複数ボリュームを持つコンテナを指定してみる

--volumes-from で複数ボリュームを持つコンテナを指定するとどうなるんやろと思って、試してみます。

結果は想定通りで、--volumes-from は指定したコンテナがマウントしている全ボリュームを、新しいコンテナからマウントできました。 1 つしかボリュームがなければ別に --mount でマウントしても良いんじゃねと思ったんですが、そういえば名前を明示的につけずにボリュームをマウントすることもできたので、 そういう場合にもメリットがありそうです。

# 複数ボリュームをマウントしたコンテナを作る
$ docker run --name multi-volumes -it --mount source=vol,destination=/vol1 --mount source=vol2,destination=/vol2 ubuntu

# volumes-from で上記コンテナを指定したコンテナをつくる
% docker run --rm \
             --volumes-from multi-volumes \
             -it ubuntu /bin/bash
root@6d59bc95c759:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  vol1  vol2
root@6d59bc95c759:/# ls vol*
vol1:
hello.txt

vol2:
root@6d59bc95c759:/#

バックアップ

対象コンテナがマウントしている volume がわかればバックアップもできるということで、以下のようなかんじでバックアップがとれます。

$ docker run --rm \
             --volumes-from multi-volumes:ro \
             --mount type=bind,src="$(pwd)/backup",dst=/backup \
             -it ubuntu 
                 tar czvf /backup/bk.tgz /vol1 /vol2
tar: Removing leading `/' from member names
/vol1/
/vol1/hello.txt
/vol2/

参考文献