PodmanのVolumeを使ってMySQLを永続化する

# はじめに

[前回の記事](https://qiita.com/t-kigi/items/a14dfd3c2c1620f54c43) に引き続いて、Docker の代わりに Podman を使うためにどのような差分があるのかを見ていく。

## Podman Volume

MySQLなどをサーバー上で利用する場合、ボリュームを永続化しておく必要がよい (そうしないと、コンテナの削除などでデータが消えてしまうなど問題が出る)。 この時、Docker では `docker volume` で永続化したボリュームを作成してこれを利用する。
Podman の場合も同様に `podman volume` コマンドがあるので、これを利用してボリュームを作成できる。 この時は Podman で用意されたと考えられるデフォルトディレクトリがマウントされる。

```bash:Mountpointを参照
# rootless の場合
$ podman volume create sample
sample
$ podman volume inspect sample
[
     {
          "Name": "sample",
          "Driver": "local",
          "Mountpoint": "/home/centos/.local/share/containers/storage/volumes/sample/_data",
          "CreatedAt": "2020-07-13T17:41:12.27273779+09:00",
          "Labels": {
               
          },
          "Scope": "local",
          "Options": {
               
          },
          "UID": 0,
          "GID": 0,
          "Anonymous": false
     }
]

# rootful な場合
$ sudo podman volume create sudo-sample
sudo-sample
$ sudo podman volume inspect sudo-sample
[
     {
          "Name": "sudo-sample",
          "Driver": "local",
          "Mountpoint": "/var/lib/containers/storage/volumes/sudo-sample/_data",
          "CreatedAt": "2020-07-13T17:41:58.770498487+09:00",
          "Labels": {
               
          },
          "Scope": "local",
          "Options": {
               
          },
          "UID": 0,
          "GID": 0,
          "Anonymous": false
     }
]
```

## 特定パスをマウントしたボリュームの作成

個人的には特定のパス (例えば、 `/opt/mount/mysql` )をマウントポイントにしたい、といったケースがある。
この場合、Docker では [例えばこちらの記事にあるように](https://blog.moo-channel.net/2017/04/24/docker-composenototupureberuvolumesdehosutonodeirekutoriwomauntosuru-2/) docker-compose.yml に以下のような記述を書いて volume をマウントしていた。

```yaml:特定ディレクトリをマウントしたVolumeを作成するためのdocker-compose.ymlの一部
volumes:
  datastore:
    driver_opts:
      type: none
      device: /opt/mount/mysql
      o: bind
```

これは同様の方法の内容を `podman` コマンドで実現して、ボリュームを作成できる。

```bash
$ podman volume create -o type=none -o device=/opt/mount/mysql -o o=bind datastore
```

ただ、この方法で作成したボリュームは rootful でなければマウントできないようだ。
そのため、もしこの方法を使うというのであれば rootful なコンテナに対して利用する。

```bash
$ podman run --rm -v datastore:/tmp2 nginx touch /tmp2/hoge
Error: error mounting volume datastore for container 549045ccdd392987427598764ffc0b533fdb5d6a6b31bd4172aa28282bc15e2d: cannot mount volumes without root privileges: operation requires root privileges
```

……のだが、ルートで実行するとどうなるか。 以下の通り Permission denied ではじかれてしまう。 ディレクトリパーミッションが `777` であるにも関わらず、である。

```
# パーミッションは問題ない
$ ls -l /opt/mount/
total 0
drwxrwxrwx. 2 root root 6 Jul 13 18:00 mysql

$ sudo podman run --rm -v datastore:/tmp2 nginx touch /tmp2/hoge
touch: cannot touch '/tmp2/hoge': Permission denied
```

## マウントボリュームが `Permission denied`

今回の検証環境が RedHat 系ということで、心当たりがある人がいるかもしれないが、結論から言えば原因は SELinux である。 今回の検証環境では `sestatus = enabled` の状態で検証している。 [公式のトラブルシュートで２番目に述べられている](https://github.com/containers/podman/blob/master/troubleshooting.md)通り、非常に多くの人が引っかかる問題のようだ。 紹介されている解消法は2つ。

- `-v` の第三引数として `:z` あるいは `:Z` オプションをつける
  - Docker にも存在するオプションで、SELinux用のラベルの付け替えを行う
- `--security-opt label=disable` を指定することでコンテナに対するセキュリティラベリングを無効化する
  - こちらも同様にDockerにも存在するオプション

今回は後者のオプションをつけて、SELinuxのセキュリティラベリングを無効化して動作させる。 これでマウントができていることが確認できた。

```bash:指定したマウントディレクトリに結果が出ていることを確認
$ sudo podman run --security-opt label=disable --rm -v datastore:/tmp2 nginx touch /tmp2/hoge
$ ls -l /opt/mount/mysql/
total 0
-rw-r--r--. 1 root root 0 Jul 13 18:28 hoge
```

## MySQL の永続化

ということで本題。 一度 `sudo podman rm -af && sudo podman volume rm -af` を実施して、一通り削除してから開始します。

```bash
# ボリューム datastore を作成
$ sudo podman volume create -o type=none -o device=/opt/mount/mysql -o o=bind datastore
datastore
# マウントしてMySQLを起動
$ sudo podman run --security-opt label=disable -d -v datastore:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=sample mysql 
a40dc20b6246411acc57bb0c7b19825579f95acfe25296685009f7c89e1a9c18
# MySQL DBに接続してデータベースを作成 (内容を変化させる)
$ sudo podman exec -it a40 mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.20 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database hogehoge;
Query OK, 1 row affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| hogehoge           |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> 
mysql> exit;
Bye
# マウントしたホストのディレクトリにデータが書き込まれていることを確認
$ ls -l /opt/mount/mysql/
total 186776
-rw-r-----. 1 systemd-coredump input       56 Jul 13 18:34  auto.cnf
-rw-r-----. 1 systemd-coredump input  3104223 Jul 13 18:34  binlog.000001
-rw-r-----. 1 systemd-coredump input      353 Jul 13 18:34  binlog.000002
-rw-r-----. 1 systemd-coredump input       32 Jul 13 18:34  binlog.index
-rw-------. 1 systemd-coredump input     1680 Jul 13 18:34  ca-key.pem
-rw-r--r--. 1 systemd-coredump input     1112 Jul 13 18:34  ca.pem
-rw-r--r--. 1 systemd-coredump input     1112 Jul 13 18:34  client-cert.pem
-rw-------. 1 systemd-coredump input     1676 Jul 13 18:34  client-key.pem
drwxr-x---. 2 systemd-coredump input        6 Jul 13 18:34  hogehoge
-rw-r-----. 1 systemd-coredump input   196608 Jul 13 18:34 '#ib_16384_0.dblwr'
-rw-r-----. 1 systemd-coredump input  8585216 Jul 13 18:34 '#ib_16384_1.dblwr'
-rw-r-----. 1 systemd-coredump input     5642 Jul 13 18:34  ib_buffer_pool
-rw-r-----. 1 systemd-coredump input 12582912 Jul 13 18:34  ibdata1
-rw-r-----. 1 systemd-coredump input 50331648 Jul 13 18:34  ib_logfile0
-rw-r-----. 1 systemd-coredump input 50331648 Jul 13 18:34  ib_logfile1
-rw-r-----. 1 systemd-coredump input 12582912 Jul 13 18:34  ibtmp1
drwxr-x---. 2 systemd-coredump input      187 Jul 13 18:34 '#innodb_temp'
drwxr-x---. 2 systemd-coredump input      143 Jul 13 18:34  mysql
-rw-r-----. 1 systemd-coredump input 30408704 Jul 13 18:34  mysql.ibd
drwxr-x---. 2 systemd-coredump input     8192 Jul 13 18:34  performance_schema
-rw-------. 1 systemd-coredump input     1680 Jul 13 18:34  private_key.pem
-rw-r--r--. 1 systemd-coredump input      452 Jul 13 18:34  public_key.pem
-rw-r--r--. 1 systemd-coredump input     1112 Jul 13 18:34  server-cert.pem
-rw-------. 1 systemd-coredump input     1680 Jul 13 18:34  server-key.pem
drwxr-x---. 2 systemd-coredump input       28 Jul 13 18:34  sys
-rw-r-----. 1 systemd-coredump input 10485760 Jul 13 18:34  undo_001
-rw-r-----. 1 systemd-coredump input 12582912 Jul 13 18:34  undo_002
```

上で作ったコンテナ・ボリュームをわざと削除して、データが削除されていないかを確認します。

```bash
# Podman上のコンテナとボリュームを全削除
$ sudo podman rm -af 
a40dc20b6246411acc57bb0c7b19825579f95acfe25296685009f7c89e1a9c18
$ sudo podman volume rm -af 
datastore

# 再度ボリュームをマウントし、MySQLコンテナを生成
$ sudo podman volume create -o type=none -o device=/opt/mount/mysql -o o=bind datastore
datastore
# -- NOTE: ここで既に初期化済の MySQL データをバインドしているのでパスワードは不要
$ sudo podman run --security-opt label=disable -d -v datastore:/var/lib/mysql mysql 
a5a2dc5121ce3bacc805d2f3a227af4f43edb48c083a4ca8c381029f38cc1c5e

# 消去したPodmanのボリューム内に変更されたデータがローカル側にバインドされていることを確認
# (Database: hogehoge が存在する)
$ sudo podman exec -it a5a mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.20 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| hogehoge           |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)
```

ということで永続化ができていることが確認できます。


# まとめ

この部分はほとんど Docker と同じでした。