通常、データベースのコンテナのデータ永続化には、データコンテナを使う方法がよく知られていますが、やはり外部のディスクをマウントしてそこに保存したくなります。
しかし、単純に NFS 等でマウントしたフォルダに対して直接データを保存しようとすると権限がらみでエラーを起こす場合があります。
例えば、Vagrant を使って↓こんな感じで MariaDB を起動しようと vagrant up
すると、
(Vagrantfile から一部抜粋)
config.vm.synced_folder "./mariadb", "/mariadb", type: "nfs"
config.vm.provision :docker do |docker|
docker.pull_images "mariadb"
docker.run "mariadb",
image: "mariadb",
args: [
"-e MYSQL_ROOT_PASSWORD=test",
"-v /mariadb:/var/lib/mysql"
].join(" "),
restart: false
end
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
72c9a74e6fcc mariadb "/docker-entrypoint.s" 7 seconds ago Exited (1) 6 seconds ago mariadb
$ docker logs mariadb
chown: changing ownership of '/var/lib/mysql/': Operation not permitted
と、なってしまいます。
では、まず一つ目の解決方法は、
Vagrant の NFS のオプションを使って、強制的にマウント先に root 権限を渡してしまう危険な方法。
config.vm.synced_folder "./mariadb", "/mariadb", type: "nfs"
config.nfs.map_uid = 0
config.nfs.map_gid = 0
config.vm.provision :docker do |docker|
docker.pull_images "mariadb"
docker.run "mariadb",
image: "mariadb",
args: [
"-e MYSQL_ROOT_PASSWORD=test",
"-v /mariadb:/var/lib/mysql"
].join(" "),
restart: false
end
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
90969077c350 mariadb "/docker-entrypoint.s" 7 seconds ago Up 6 seconds 3306/tcp mariadb
$ ls -la /mariadb
total 110648
drwxr-xr-x 11 999 999 374 Apr 12 17:36 ./
drwxr-xr-x 17 root root 420 Apr 12 17:35 ../
-rw-rw---- 1 999 999 16384 Apr 12 17:36 aria_log.00000001
-rw-rw---- 1 999 999 52 Apr 12 17:36 aria_log_control
-rw-rw---- 1 999 999 50331648 Apr 12 17:36 ib_logfile0
-rw-rw---- 1 999 999 50331648 Apr 12 17:36 ib_logfile1
-rw-rw---- 1 999 999 12582912 Apr 12 17:36 ibdata1
-rw-rw---- 1 999 999 0 Apr 12 17:36 multi-master.info
drwx------ 89 999 999 3026 Apr 12 17:36 mysql/
drwx------ 3 999 999 102 Apr 12 17:36 performance_schema/
-rw-rw---- 1 root 999 24576 Apr 12 17:36 tc.log
まあ、動くには動くんですが、これはかなりまずいですね。
一部のフォルダとは言え、root 権限を export してしまうのは問題ありです。
そこで登場するのが bindfs
mount --bind
と同様に既存のフォルダを別のフォルダにバインド(マウント)するのがお仕事なんですが、それと同時に、ファイル/フォルダのオーナーやグループ、パーミッションを変更、制御しつつ、マウントしてくれるのが特徴です。
以下のように、NFS で export されているローカルの UID/GID
を mysql(999)/mysql(999) に map しつつ、/mariadb
を ~/mariadb
にマウントさせると、
UID=`id -u`.strip
GID=`id -g`.strip
config.vm.synced_folder "./mariadb", "/mariadb", type: "nfs"
config.vm.provision :shell do |sh|
sh.inline = <<-EOT
mkdir -p ~/mariadb
bindfs --map=#{UID}/999:@#{GID}/@999 /mariadb ~/mariadb
EOT
end
config.vm.provision :docker do |docker|
docker.pull_images "mariadb"
docker.run "mariadb",
image: "mariadb",
args: [
"-e MYSQL_ROOT_PASSWORD=test",
"-v ~/mariadb:/var/lib/mysql"
].join(" "),
restart: false
end
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8f0c1fb44d73 mariadb "/docker-entrypoint.s" 4 seconds ago Up 3 seconds 3306/tcp mariadb
うまくいきました!
$ ls -la /mariadb
total 110648
drwxr-xr-x 11 501 20 374 Apr 12 17:42 ./
drwxr-xr-x 17 root root 420 Apr 9 17:42 ../
-rw-rw---- 1 501 20 16384 Apr 12 17:42 aria_log.00000001
-rw-rw---- 1 501 20 52 Apr 12 17:42 aria_log_control
-rw-rw---- 1 501 20 50331648 Apr 12 17:42 ib_logfile0
-rw-rw---- 1 501 20 50331648 Apr 12 17:42 ib_logfile1
-rw-rw---- 1 501 20 12582912 Apr 12 17:42 ibdata1
-rw-rw---- 1 501 20 0 Apr 12 17:42 multi-master.info
drwx------ 89 501 20 3026 Apr 12 17:42 mysql/
drwx------ 3 501 20 102 Apr 12 17:42 performance_schema/
-rw-rw---- 1 501 20 24576 Apr 12 17:42 tc.log
$ sudo ls -la /root/mariadb
total 110648
drwxr-xr-x 11 999 999 374 Apr 12 17:42 .
drwx------ 3 root root 80 Apr 12 17:41 ..
-rw-rw---- 1 999 999 16384 Apr 12 17:42 aria_log.00000001
-rw-rw---- 1 999 999 52 Apr 12 17:42 aria_log_control
-rw-rw---- 1 999 999 50331648 Apr 12 17:42 ib_logfile0
-rw-rw---- 1 999 999 50331648 Apr 12 17:42 ib_logfile1
-rw-rw---- 1 999 999 12582912 Apr 12 17:42 ibdata1
-rw-rw---- 1 999 999 0 Apr 12 17:42 multi-master.info
drwx------ 89 999 999 3026 Apr 12 17:42 mysql
drwx------ 3 999 999 102 Apr 12 17:42 performance_schema
-rw-rw---- 1 999 999 24576 Apr 12 17:42 tc.log
ls
の出力で見られるように、NFS のマウント先ではローカルのオーナーに、
bindfs
で作られたバインド先では、mysql(999)
がオーナーになっているのがわかります。
これで、vagrant destroy
しても、再度 vagrant up
すれば、データはそのまま引き続き使うことが出来ます。
これ、wocker と一緒に使えないかなぁ。
ちなみに、完全な Vagrantfile はこちらです。
https://gist.github.com/ailispaw/4c90d9f2086ae388f998ed0c809e820c