bindfs を使った MariaDB(MySQL) コンテナのデータ永続化（NFS編）

通常、データベースのコンテナのデータ永続化には、データコンテナを使う方法がよく知られていますが、やはり外部のディスクをマウントしてそこに保存したくなります。

しかし、単純に NFS 等でマウントしたフォルダに対して直接データを保存しようとすると権限がらみでエラーを起こす場合があります。

例えば、Vagrant を使って↓こんな感じで MariaDB を起動しようと `vagrant up` すると、

（Vagrantfile から一部抜粋）

```ruby
  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
```

```bash
$ 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 権限を渡してしまう危険な方法。

```ruby
  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
```

```bash
$ 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](http://bindfs.org/)

`mount --bind` と同様に既存のフォルダを別のフォルダにバインド（マウント）するのがお仕事なんですが、それと同時に、ファイル／フォルダのオーナーやグループ、パーミッションを変更、制御しつつ、マウントしてくれるのが特徴です。

以下のように、NFS で export されているローカルの `UID/GID` を mysql(999)/mysql(999) に map しつつ、`/mariadb` を `~/mariadb` にマウントさせると、

```ruby
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
```

```bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
8f0c1fb44d73        mariadb             "/docker-entrypoint.s"   4 seconds ago       Up 3 seconds        3306/tcp            mariadb
```

うまくいきました！

```bash
$ 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](http://wckr.github.io/) と一緒に使えないかなぁ。

ちなみに、完全な Vagrantfile はこちらです。
https://gist.github.com/ailispaw/4c90d9f2086ae388f998ed0c809e820c