MariaDB (MySQL) がある VMware 仮想マシンのバックアップとデータベースの復旧を Commvault を使って試してみる

注: 以下は動作を理解するための検証内容とその結果です。本番環境への適用については、きちんとサイジングや事前検証をするようにしてください。

VADP 連携による VMware 仮想マシンのバックアップでしばしば議論になる、データベースの静止点確保問題。

ゲスト OS 上にバックアップ ソフトのエージェント入れればバックアップ取れますが、VADP バックアップと VMware の機能でやるとどうバックアップ / リストアできるか、MariaDB 使って試してみました。 

# バックアップ対象仮想マシンの準備

今回は CentOS 7.6 を使用しています。

    # cat /etc/centos-release
    CentOS Linux release 7.6.1810 (Core)
    #

## Open VM Tools のインストール

VADP 連携による仮想マシンのバックアップでは、仮想マシンのスナップショットを使用します。Open VM Tools (VMware Tools) がインストールされている仮想マシンでは、スナップショット作成時にゲスト OS 上にインストールされたスクリプトを実行することができるので、今回はこのスクリプトから MariaDB のロックおよびロック解除のコマンドを実行させます。

yum で open-vm-tools もインストールします。

    # yum install open-vm-tools -y
    #

vmtoolsd.service を有効にしておきます。

    # systemctl enable vmtoolsd.service
    # systemctl start vmtoolsd.service
    #

スナップショット作成時に使用するスクリプトは後ほど・・・

## データベース (MariaDB) の準備

MariaDB とテスト用のデータベース、および表を構成します。

### MariaDB のインストール

yum で MariaDB をインストールします。

    # yum install mariadb-server.x86_64 -y
    #

MariaDB を自動起動するようにしておきます。

    # systemctl enable mariadb
    Created symlink from /etc/systemd/system/multi-user.target.wants/mariadb.service to /usr/lib/systemd/system/mariadb.service.
    # systemctl start mariadb
    #

### テスト用のデータベース、表の構成およびデータの登録

mysql コマンドで MariaDB にログインします。

    # mysql -u root
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 2
    Server version: 5.5.65-MariaDB MariaDB Server
    
    Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    MariaDB [(none)]>

DB01 データベースを作成して、DB01 データベースに接続します。

    MariaDB [(none)]> CREATE DATABASE DB01;
    Query OK, 1 row affected (0.00 sec)
    
    MariaDB [(none)]> use DB01;
    Database changed
    MariaDB [DB01]>

テスト用の表を作成します。復旧時にどの時点まで戻ったかを確認するために、TIME 列には INSERT 文を発行した時間を入れるようにします。

    MariaDB [DB01]> CREATE TABLE TABLE01 (ID INT NOT NULL AUTO_INCREMENT, DATA VARCHAR(32), TIME TIMESTAMP, PRIMARY KEY (ID));
    Query OK, 0 rows affected (0.00 sec)
    
    MariaDB [DB01]>

INSERT 文を発行して表にデータを挿入します。その後、SELECT 文を発行して意図しているデータが入っているか確認してみます。

    MariaDB [DB01]> INSERT INTO TABLE01 (DATA, TIME) VALUES (MD5(RAND()), NOW());
    Query OK, 1 row affected (0.01 sec)
    
    MariaDB [DB01]> INSERT INTO TABLE01 (DATA, TIME) VALUES (MD5(RAND()), NOW());
    Query OK, 1 row affected (0.00 sec)
    
    MariaDB [DB01]> INSERT INTO TABLE01 (DATA, TIME) VALUES (MD5(RAND()), NOW());
    Query OK, 1 row affected (0.00 sec)
    
    MariaDB [DB01]> select * from TABLE01;
    +----+----------------------------------+---------------------+
    | ID | DATA                             | TIME                |
    +----+----------------------------------+---------------------+
    |  1 | e1e750366757e64f028581fdae0cbeb2 | 2020-05-28 17:07:30 |
    |  2 | 7cb2894d667e43b29d76faf7c15e67c2 | 2020-05-28 17:07:32 |
    |  3 | 11cc5d0f2396ff337cfe17b8cf99f4a0 | 2020-05-28 17:07:35 |
    +----+----------------------------------+---------------------+
    3 rows in set (0.00 sec)
    
    MariaDB [DB01]>

問題ないことを確認したら、ログアウトします。

    MariaDB [DB01]> exit
    Bye
    #

テスト時には、以下のようなシェルスクリプトを発行して、INSERT 文を無限ループで回します。

    # while true
    > do
    > date
    > mysql -uroot DB01 -e'INSERT INTO TABLE01 (DATA, TIME) VALUES (MD5(RAND()), NOW())'
    > sleep 1
    > done
    Thu May 28 17:20:02 JST 2020
    Thu May 28 17:20:03 JST 2020
    Thu May 28 17:20:04 JST 2020
    Thu May 28 17:20:05 JST 2020
    Thu May 28 17:20:06 JST 2020
    Thu May 28 17:20:07 JST 2020
    ^C
    #


## カスタム静止スクリプトの構成 

Commvault のドキュメントサイト ( http://documentation.commvault.com/commvault/v11/article?p=32208.htm ) では、MySQL (MariaDB) 用のカスタム静止スクリプトのサンプルとして、Python のスクリプトをアップロードしていますが、すべての環境に Python が入ってはいないなず。

また、Python のスクリプトにいろいろ書いてありますが、MySQL の静止点確保の仕組みとしては、`FLUSH TABLES WITH READ LOCK` でテーブル ロックした後に仮想マシンのスナップショットを作成して、その後 `UNLOCK TABLES` でロック解除する流れらしいので、以下のような簡単なスクリプトを作りました。

### pre-freeze-script

`pre-freeze-script` では、実行した時間を /scripts/pre-freeze-script.log に記録して、`FLUSH TABLES WITH READ LOCK` を投げます。

    # cat /usr/sbin/pre-freeze-script
    #!/bin/bash
    
    date >> /scripts/pre-freeze-script.log
    
    mysql -uroot -e'FLUSH TABLES WITH READ LOCK'
    #

### post-thaw-script

`post-thaw-script` では、実行した時間を /scripts/pre-freeze-script.log に記録して、`UNLOCK TABLES` を投げます。

    # cat /usr/sbin/post-thaw-script
    #!/bin/bash
    
    date >> /scripts/post-thaw-script.log
    
    mysql -uroot -e'UNLOCK TABLES'
    #


# 仮想マシンのバックアップ

Commvault では、**ファイル システムとアプリケーション コンシステント** オプションを選択して仮想マシンのバックアップを実行します。このオプションを選択すると、VMware Tools (Open VM Tools) のカスタム静止スクリプトを実行します。

(1) バックアップ ジョブの開始前に INSERT 文の無限ループを実行します。

    # while true
    > do
    > date
    > mysql -uroot DB01 -e'INSERT INTO TABLE01 (DATA, TIME) VALUES (MD5(RAND()), NOW())'
    > sleep 1
    > done
    Thu May 28 20:51:12 JST 2020
    Thu May 28 20:51:13 JST 2020
    Thu May 28 20:51:14 JST 2020
    Thu May 28 20:51:15 JST 2020
    Thu May 28 20:51:16 JST 2020
    ...

(2) バックアップ ジョブを実行します。

(3) バックアップ終了後、無限ループ終了します。

(4) pre-freeze-script.log と post-thaw-script.log の内容を確認します。

    # tail -n 1 /scripts/pre-freeze-script.log
    Thu May 28 20:51:49 JST 2020
    # tail -n 1 /scripts/post-thaw-script.log
    Thu May 28 20:51:53 JST 2020
    #

Thu May 28 20:51:49 JST 2020 から Thu May 28 20:51:53 JST 2020 の間のデータベースがバックアップされているはず。

(5) データベースに格納されているデータを確認します。以下の SQL 文では最新の時刻を表示しています。

    # mysql -uroot DB01 -e'SELECT MAX(TIME) FROM TABLE01'
    +---------------------+
    | MAX(TIME)           |
    +---------------------+
    | 2020-05-28 21:08:51 |
    +---------------------+
    #

Thu May 28 20:51:53 JST 2020 (/scripts/post-thaw-script.log に書き込まれた時間) よりも後のデータが入ってます。

# リストアによるデータベースの復旧について

Commvault では、VMware 仮想マシンのバックアップからは、以下の 3 パターンの仮想マシンのリストアが可能です。

- 仮想マシン全体のリストア
    - バックアップした仮想マシンを丸ごとリストアします。静止点が確保された状態で正常起動すればデータベースも復旧します。シンプルですがデータベース以外のファイルも丸ごと復旧されます。
- 仮想マシン上のファイルのリストア
    - 仮想マシンのバックアップに含まれるファイル単位のリストアを行ないます。データベースのみ復旧したいような場合はこの方式が良いかもしれません。
- 仮想ディスクのリストア
    - 既存の VM に VMDK ファイルをアタッチします。OS 上のコマンド使ってファイルをコピーします。このドキュメントでの説明は省略します。


## 仮想マシンのリストアによるデータベースの復旧

バックアップ元のデータベースと比較ができるようにするために、元の仮想マシンとは別の仮想マシンとしてリストアしてみます。

[仮想マシンの表示名を変更] 列の値を変更することでリストア先の仮想マシン名を変更することができます。以下では kwvc01-vm04 を kwvc01-vm04r という名前でリストアしています。
![WS000034.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482950/6ab1d4bd-c603-2d9f-a32d-1242d9b2a353.png)

リストア後、仮想マシンを起動して、pre-freeze-script.log と post-thaw-script.log に書き込まれた最後の時間を確認します。

    # tail -n 1 /scripts/pre-freeze-script.log
    Thu May 28 20:51:49 JST 2020
    # tail -n 1 /scripts/post-thaw-script.log
    Thu May 28 17:58:48 JST 2020
    #

pre-freeze-script.log に書き込まれた時間よりも post-thaw-script.log に書き込まれた時間のほうが前になっていますが、pre-freeze-script 実行後、post-thaw-script 実行前のタイミングでスナップショット (仮想ディスクの静止点) が取得されているので正しい状態です。

この出力から、Thu May 28 20:51:49 JST 2020 (2020-05-28 20:51:49) 直後のデータが DB に入っているはず。

TABLE01 の最新の時間を確認してみます。

    # mysql -uroot DB01 -e'SELECT MAX(TIME) FROM TABLE01'
    +---------------------+
    | MAX(TIME)           |
    +---------------------+
    | 2020-05-28 20:51:50 |
    +---------------------+
    #

想定通りの状態に戻っています。

## MariaDB のデータ ファイルのリストアによるデータベースの復旧

今度は仮想マシン全体では無く、MariaDB のデータ ファイルのみのリストアをして、データベースの復旧を行ないます。
データベースの静止点を確保後、データベースのファイルをコピーしてバックアップしている運用における復旧シナリオに似ています。

Linux 仮想マシンのバックアップからファイル単位のリストアを行なうには、File Recovery Enabler for Linux (FREL) を準備していただくか、Linux OS 上に Virtual Server Agent (VSA) をインストールしていただく必要があります。

### リストアの準備 (データベースの削除)

MariaDB のデータ フォルダを丸ごと移動して、データベースのファイルが削除され、MariaDB が起動しない状態を作ります。

(1) MariaDB のデーモンを停止します。

    # service mariadb stop
    Redirecting to /bin/systemctl stop mariadb.service
    # 

(2) MariaDB のデータ フォルダを移動します。

    # mv /var/lib/mysql /var/lib/mysql.bak
    #

(3) MariaDB のデーモンを起動して、起動しないことを確認します。

    # service mariadb start
    Redirecting to /bin/systemctl start mariadb.service
    Job for mariadb.service failed because the control process exited with error code. See "systemctl status mariadb.service" and "journalctl -xe" for details.
    #

### 仮想マシンのバックアップからファイル単位のリストア

/var/lib/mysql フォルダ以下のファイルを /var/lib フォルダにリストアします。

Commvault による VMware 仮想マシンのバックアップでは、VMware Tools と連携した Agentless リストア機能を使用することが可能です。シンボリックリンクの情報が戻らない等の制限はありますが、仮想マシンの OS とバックアップ サーバー間で通信ができる必要はないというメリットがあります。

Agentless リストアの大まかな流れは以下の通りです。

(1) [ブラウズとリストア オプション] ダイアログが表示されたら、[ゲスト ファイルおよびフォルダ] を選択して [次へ] をクリックします。
![WS000022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482950/44e56cca-f6f2-46dc-1146-a2774cf67e71.png)

(2) 仮想マシンのディレクトリ ツリーが表示されたら、/var/lib/mysql フォルダを選択して、[選択対象をすべてリカバリ] をクリックします。
![WS000024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482950/440e509b-1655-96b8-cdb5-6f4d91d38919.png)


(3) [選択された全項目のリストア オプション] ダイアログが表示されたら、[仮想マシンにリストア] を選択します。
![WS000027.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482950/b0c381c3-4bd3-fb59-e7ef-745dc4fe8ce3.png)

(4) [プロキシ クライアント] リストからリストアで使用するホストを選択し、[仮想マシン] オプション右側にある [...] をクリックして、リストア先の仮想マシンを選択します。
![WS000029.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482950/412e8f2a-ce7f-3f45-f4e7-720ca4296c88.png)

(5) [仮想マシン] オプションの値がリストア先の仮想マシン (kwvc01-vm04r) に変更されたことを確認後、ゲスト OS の資格情報、および [宛先パスを指定] オプションにリストア先のフォルダ /var/lib を入力して [OK] をクリックします。
![WS000032.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482950/7a897b1f-9730-1604-2d34-529cb5fcf3e1.png)


### データベースの復旧確認

MariaDB のデーモンを起動して、想定している状態にデータベースが復旧することを確認します。

(1) /var/lib/mysql フォルダがリストアされていることを確認します。

    # ls -al /var/lib/ | grep mysql
    drwxr-xr-x   6 mysql   mysql    171 May 28 16:53 mysql
    drwxr-xr-x   6 mysql   mysql    171 May 28 22:16 mysql.bak
    #

(2) MariaDB のデーモンを起動し、正常に起動することを確認します。
(SELinux 有効になってると起動しないことがあります。今回の環境では事前に無効化していあります。)

    # service mariadb start
    Redirecting to /bin/systemctl start mariadb.service
    #

(3) 仮想マシンのリストアで戻った状態と同じ状態になっていることが確認できました。

    # mysql -uroot DB01 -e'SELECT MAX(TIME) FROM TABLE01'
    +---------------------+
    | MAX(TIME)           |
    +---------------------+
    | 2020-05-28 20:51:50 |
    +---------------------+
    #