Carpe Diem

備忘録

Docker Data Volume を理解する

概要

Dockerのデータをホスト側に保持する方法をまとめます。
Dockerはコンテナの破棄・再作成が簡単にできる一方、そのままだとデータも消えてしまいます。
今回のDate Volumeはデータの永続性を保つべきシーンで必要となる知識です。

環境

  • OSX 10.11.4
  • docker 1.11.0
  • docker-machine 0.7.0

4つのパターン

docker runするときに以下のオプションをつけると使えます。

  1. -v <container_path>
  2. -v <host_path>:<container_path>
  3. -v <data_volume>:<container_path>
  4. --volumes-from <container_name>

これらを順に説明していきます。

通常のDocker run

今回はubuntuのimageを使います。

$ docker run -it --name my-data ubuntu /bin/bash

通常だとデータはコンテナ内のみに残るので、コンテナを破棄するとデータも消えてしまいます。
これに先ほどのオプションをつけてデータの永続化をします。

a. -v <container_path>

コマンド

$ docker run -it --name my-data -v /hoge ubuntu /bin/bash

同期されるフォルダ

マシン フォルダ
コンテナ /hoge。存在しないフォルダなら自動生成される
ホスト /var/lib/docker/volumes/<ランダムな文字列>/_data/に同期される

同期確認

コンテナ側

適当なファイルを作成します。

root@fab1e6ce7428:/# cd /hoge/
root@fab1e6ce7428:/hoge# touch feee
root@fab1e6ce7428:/hoge# ls
feee

ホスト側

# cd /var/lib/docker/volumes/b3beace9176f1631d02f6398a7df4c201c67f7a49adb6087aa1add9958385568/_data
# ls
feee

ちゃんとファイルが存在します。

b. -v <host_path>:<container_path>

bind mountとも呼ばれる方式です。

コマンド

$ docker run -it --name my-data -v /fuga:/hoge ubuntu /bin/bash

同期されるフォルダ

マシン フォルダ
コンテナ /hoge。存在しないフォルダなら自動生成される
ホスト /fugaに同期される。
fugaのように、ルートから始めない場合
c のdata volumeとして扱われる

同期確認

コンテナ側

適当なファイルを作成します。

root@fab1e6ce7428:/# cd /hoge/
root@fab1e6ce7428:/hoge# touch feee
root@fab1e6ce7428:/hoge# ls
feee

ホスト側

$ cd /fuga/
# ls
feee

ちゃんとファイルが存在します。

注意

bind mountの場合、ホスト側のデータに同期されるためコンテナ側で指定したディレクトリに既存のファイルがあったとしても見えなくなります。

ref: バインドマウントの利用 | Docker ドキュメント

c. -v <data_volume>:<container_path>

コマンド

$ docker run -it --name my-data -v some_data:/hoge ubuntu /bin/bash

同期されるフォルダ

マシン フォルダ
コンテナ /hoge。存在しないフォルダなら自動生成される
ホスト docker volumeにsome_dataが追加される。
また/var/lib/docker/volumes/some_dataに実体ができる

同期確認

コンテナ側

適当なファイルを作成します。

root@fab1e6ce7428:/# cd /hoge/
root@fab1e6ce7428:/hoge# touch feee
root@fab1e6ce7428:/hoge# ls
feee

ホスト側

$ cd /var/lib/docker/volumes/some_data
# ls
feee

ちゃんとファイルが存在します。また

$ docker volume ls
DRIVER              VOLUME NAME
local               some_date

docker volumeの一覧にも登録されます。

d. --volumes-from <container_name>

これは同期設定した別コンテナを用意し、それを利用するパターンです。

同期設定したコンテナを用意

another-containerというコンテナを用意します。

$ docker run --name another-container -v /piyo:/hoge busybox

busyboxと言うのはデータ用コンテナでよく使われるimageです。
このコンテナはフォアグラウンドで起動している必要はありません。


同期されるフォルダ

マシン フォルダ
コンテナ /hoge。存在しないフォルダなら自動生成される
ホスト /piyoに同期される。
piyoのように、ルートから始めない場合
/var/lib/docker/volumes/piyoにできる

コマンド

$ docker run -it --name my-data --volumes-from another-container ubuntu /bin/bash

同期されるフォルダ

another-containerの設定の通りです。


同期確認

コンテナ側

適当なファイルを作成します。

root@fab1e6ce7428:/# cd /hoge/
root@fab1e6ce7428:/hoge# touch feee
root@fab1e6ce7428:/hoge# ls
feee

ホスト側

$ cd /piyo/
# ls
feee

ちゃんとファイルが存在します。

その他

volume一覧を見たい時

$ docker volume ls
DRIVER              VOLUME NAME
local               04566d1da2b17a53229d2dc17ea24c51e94a61806f8bb866f5822be477d03875
local               129bdd40ce9ba5344b3760dcac8691605546224a8002077e8bc837fdd0464171
local               298358023d1fd03cc47cce2fc384f569f1d5152946546a154e7d42a6237b7749
local               50974a5f0b1aeb09d7b5c7cae492c648d7cd00e73403c51ff163c6fe8bdbf530
local               728dc999bc7c2c5a15c20cbf483000042bbdcdef5ae12413c6199c1ba91b330e

残ったdocker volumeをまとめて消したい時

-qオプションをつけるとIDのみ表示されるので、それをxargsで渡すとまとめて消せます。

$ docker volume ls -q | xargs docker volume rm

コンテナの中に入りたい時

$ docker exec -it <コンテナ名> /bin/bash

ホストVMの中に入りたい時

docker-machineで動かしている場合はホストはVMなので以下のようにして入ります。

$ docker-machine ssh <VM名>

明示的にvolumeを作りたい

$ docker volume create --name mysql_data
$ docker volume ls
DRIVER              VOLUME NAME
local               mysql_data

明示的に作った後でcのマウントも可能

$ docker run -it --name my-data -v mysql_data:/hoge ubuntu /bin/bash

DockerfileのVOLUMEは?

-vを付けなければaと同じく

  • ホスト側:自動でvolumeが生成
  • コンテナ側:DockerfileのVOLUMEで設定されたディレクト

が同期されます。
docker rmしてコンテナを再作成した場合、過去のvolumeは再利用されません。
自動生成されたvolumeをbのようにマウントすると再利用は可能です。

まとめ

初期はホストのディレクトリを直接マウントすることでデータの永続性を担保していましたが、data volumeの機能が充実したことでdocker側からも管理しやすくなりました。
なので基本的にはcのやり方で、

  • ホスト側にデータの実体を保持する
  • docker volumeで管理できるようにする

とするのが良いかなと思います。

ソース