docker run -vとDockerfileのVOLUMEは違うのか?

はじめに

最近dockerについてプログラマのためのDocker教科書(以下教科書と呼ぶ)で勉強し始めた。

今回は、dockerを使ってデータの永続化という話でつまづいたときの整理をしたいと思う。

データの永続化とは、たとえばmysqlコンテナとデータコンテナを分けるということである。
たとえ前者を削除しても、データコンテナは別なのでデータを失うことはない。 別のバージョンのmysqlをデータコンテナにリンクさせることでポータビリティを保てるというメリットがあるわけだ。

教科書でデータ用のコンテナを作成するときに、次のDockerfileからイメージをビルドして作成している。

Dockerfile

# Dockerイメージの取得
FROM centos:latest

...(中略)...

# ボリュームの作成
VOLUME /var/log/httpd

しかしここでいくつか気になる疑問がでてきたのだ。
- ファイル内のVOLUMEが指すものは、どこに存在するものなのか?(ホストのどこか?)
- Dokcerfileでイメージをビルドしないとデータ永続用コンテナは作成できないのか?
- docker runのvオプションとはVOLUMEは別物なのか?

この疑問に関して調べた結果を残そうと思う。 先に結論を述べると、vオプションでもVOLUMEも同じである。

docker run vオプションについて

教科書には、vオプションについて次のように書かれてある。

docker run -v [ホストのディレクトリ]:[コンテナのディレクトリ]
ホストとコンテナでディレクトリを共有化する方法。

なるほど、この場合データの実態はホストに存在している。

では、次のように書くと何を意味するのか?
docker run -v /myvol -e MYSQL_ROOT_PASSWORD=mysql --name dbserver mysql

下図の通り確かにmyvolが作成されたコンテナに存在している。
が、それはどこに繋がれてる? ホストなのか?

f:id:poppon555:20190504112607p:plain

実は、/myvolは、docker volumeに接続されている。 docker volume lsと入力すると、dockerで作成されたボリュームができる。

f:id:poppon555:20190504112714p:plain

ただし-v /myvolとした場合、volume名がハッシュ化されてどの用途のボリュームなのかがわからなくなる。上図でも一つはmysqlコンテナ自体が使用しているボリュームで、もう一つは/myvolにマウントしているボリュームになるが、ハッシュ化されたVOLUME NAMEではわからない。

名前解決できない状況を回避するためには、ボリューム名を明示的に指定して作成し、それをマウントさせる。
docker volume create v1
docker run -v v1:/myvol -name dbserver mysql

v1という名前のボリュームの作成

f:id:poppon555:20190504113741p:plain

作成したボリュームをマウントする docker run -d --name dbserver -v v1:/myvol -e MYSQL_ROOT_PASSWORD=root mysql

f:id:poppon555:20190504112737p:plain

docker volume lsで確認

f:id:poppon555:20190504112752p:plain

以上よりdocker runのvオプションについてまとめると、
docker run -v [ホストのディレクトリ]:[コンテナのディレクトリ] mysql ホストと共有化
docker run -v [dokcer volume]:[コンテナのディレクトリ] mysql 名前付きボリュームを指定ディレクトリにマウント
docker run -v [コンテナのディレクトリ] mysql ハッシュ値のボリュームを指定したディレクトリにマウント
となり、最後の2つについては、起動コンテナと別のボリュームがマウントされ、名前付きかどうかが異なる

補足: rmオプションについて
docker rmでコンテナを削除しても、vオプションで作られたボリュームは同時に削除されない。

f:id:poppon555:20190504112808p:plain

コンテナが不要になったと同時に削除するには、rmオプションをつけて、docker run --rm -v v1:/myvol mysql と入力する。

f:id:poppon555:20190504112821p:plain

※それでもマウントしたv1ボリュームは削除されないことは注意

.DockerFileのVOLUMEについて

教科書には、VOLUMEについてこう書かれている。

VOLUME ["/マウントポイント"]
指定したマウントポイントをコンテナ内に作成し、ホストやその他コンテナからボリュームの外部マウントを行います

よくわかりませんね。。。
なので、実際にDockerfileをつくってやってみましょう。

.DockerFile

FROM mysql
VOLUME /myvol
ENV MYSQL_ROOT_PASSWORD mysql

docker build -t dbesrver .でイメージ作成して、
docker run -d -name db dbserverでコンテナ起動
マウント状況を確認すると、

f:id:poppon555:20190504112837p:plain

上図の通り、Dockerfileを利用した場合も新たにボリュームを作成して、VOLUMEで指定したディレクトリにマウントするという意味である。ボリュームに名前をつけていないので、起動したコンテナのボリュームの名前をハッシュ値となる。 (したがって、ボリュームが不要ならば--rmオプションを付けた起動したほうがよい。)

結果

以上まとめて、はじめの疑問に回答すると

  1. ファイル内のVOLUMEが指すものは、どこに存在するものなのか?(ホストのどこか?)

    ホストに存在するが特定のディレクトリと共有してるわけではなく、
    docker volumeとして作成された新たにボリュームを指している

  2. Dokcerfileでイメージをビルドしないとデータ永続用コンテナは作成できないのか?

    docker run -vからも作成可能

  3. docker runのvオプションとはVOLUMEは別物なのか?

    同じである。 名前付きかどうかという違いがあるぐらいだ。

というわけでした。

参考サイト

詳しく書かれてあったのでわかりやすかったです。

https://qiita.com/namutaka/items/f6a574f75f0997a1bb1d https://qiita.com/mtgto/items/aabc212a1d3f99878828 https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32