目次
ボリュームとは?
少しDockerの経験がある方は、ボリュームと聞くと、
「ホスト側のファイルやディレクトリをコンテナ側にマウントすることでしょう!」
と答えるかもしれません。もちろん間違っていませんし、僕もずっとそう思ってました。
しかし、docker-composeなどを用いてプロジェクト毎に環境構築していると、
コンテナ群を削除してもMySQLのデータなどを永続化したいなー、
と思ったことはありませんか?
結論から言うと、できます!
というより、Dockerのコンテナは永続データの保持に適していません。(コンテナ削除すると消えちゃうので。)そのため、Dockerで永続データを扱う場合は、
・共有ストレージをコンテナにマウントする(バインドマウント)
・ホストマシン上のDocker内にボリュームを作成する(ボリューム)
共有ストレージを使ったやり方は、みなさんがよく知ってる「ホスト側のファイルやディレクトリをコンテナ側にマウントする」という方法です。
ですが、せっかくなのでこの機会にDockerの
「バインドマウント」と「ボリューム」の違いについて理解して使いこなしてみませんか?
バインドマウントとボリュームの違いとは?
バインドマウント(Bind-Mount)
・ホスト側の「ファイルシステム」を利用します。
・ホスト側のファイルやディレクトリをコンテナ側にマウントします。
・プロジェクトとコンテナを削除するとデータは消えます。
いわゆる、みなさんが考えているボリュームの概念です。「ホスト側のファイルやディレクトリをコンテナ側にマウントする」、正式には、バインドマウントと言うそうです。
ボリューム(Volume)
・Dockerが用意している「データ領域」という仕組みを利用します。
・指定されたボリューム名のデータ領域をコンテナ側にマウントします。
・コンテナを削除しても永続的にデータは残ります。
こちらが、ボリュームの本当の概念です。データを永続化するたに利用する仕組みです。
ボリュームというデータ領域をDocker内に作成して、コンテナに依存させず、docker-compose.yamlで呼びだすようなイメージです。
データ領域内のボリュームを確認してみる
一覧表示
$ docker volume ls
DRIVER VOLUME NAME local 0ab872fc43c669edf........ local 0e9b40922301919f........ local 1b6ab83c45bc67bd........ local 1ea5849d2c93aa15........ local 2be18b928cc3a99d........
docker-composeでたくさんプロジェクトを作成している人は、上記のように意味を持たない文字列のボリュームがたくさん存在しているかもしれません。
理由は、docker-composeでコンテナ群を作成する際、ボリュームの指定をしていなくても必ず1つ生成してしまうからです。
なので、プロジェクトを生成する際は、最低1つは指定するように僕はしています。(方法は、後半で紹介しています。)
volumeの詳細表示
$ docker volume inspect [ ボリューム名 ]
[ { "CreatedAt": "2019-12-26T09:00:02Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/[ ボリューム名 ]/_data", "Name": "[ ボリューム名 ]", "Options": null, "Scope": "local" } ]
ハンズオン:MySQLのデータ用ボリュームをdocker-compose外で定義して使用する
では、実際に手を動かしてやってみようと思います。今回は、実際に僕が構築しているプロジェクト用MySQLのVolumesをローカルPCのDocker内に生成しようと思います。
基本的に個人アプリなどを作成するときのMySQLのデータベースは、このVolumeを使用しており、コンテナを削除してもDocker-compose.yamlでこのVolumeを指定することで、データの永続化を実現しています。
ローカルにVolumeを作成
以下のコマンドで現時点で存在するVolumeを確認できます。何もできてなくても大丈夫です。
$ docker volume ls
DRIVER VOLUME NAME local 8b7278509985f493015b50dc.............
以下のコマンドでproject-mysqlというvolumeを作成します。
$ docker volume create –name project-mysql
以下のコマンドで確認してみましょう。
$ docker volume ls
DRIVER VOLUME NAME local 8b7278509985f493015b50dc............. local project-mysql
docker-compose.yamlで既存のボリュームを指定
version: "3"
services:
mysql:
container_name: sample
image: mysql:5.7
environment:
MYSQL_DATABASE:sample
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
ports:
- 4306:3306
##1
volumes:
- mysql-data:/var/lib/mysql
networks:
- default
##2
volumes:
mysql-data:
external:
name: project-mysql
#1
services内で定義しているvolumes: は、いわゆるバインドマウントです。
実際のコンテナ内では、何を参照するか?をホスト側から明示しています。
#2
トップレベルのvolumes: は、Dockerシステム(ローカル)内に存在しているボリュームを指定しています。いわゆるボリュームです。
external: の中にnameを指定することで、docker-compose外で作成したボリュームを指定できます。
存在しない場合は、指定した名称でボリュームが生成されます。
指定しない場合は、無名(無意味な文字列)でボリュームが生成されます。
プロジェクト毎にMySQLのデータ用ボリュームを定義して使用したい場合
上記の記述とほとんど同じで、docker-compsoe.yaml内のトップレベルのvolumes: 内の記述を以下のようにするだけです。
volumes:
mysql-data:
external: false