VagrantとAnsibleでMySQLのHA構成を試す

MySQLのマスター1台、スレーブ2台、mysql-master-haのマネージャ1台の計4台構成です。
4台すべてを起動するとトータルで3.5GBほどメモリを使用しますので、ご注意ください。
手順は全部Ansibleで自動化してもよかったのですが、それだとフェイルオーバーの動作がよくわからないかと思ったので、レプリケーション、HA構成の設定は手動です。
HA構成には[mysql-master-ha](https://code.google.com/p/mysql-master-ha/)を使用します。


# 準備

VirtualBox、Vagrant、Ansibleはあらかじめインストールしておき、ターミナル上でコマンドが実行できるようにしておいてください。

OSはCentOSを使用します。
以下のコマンドでCentOS6.5のボックスを追加します。

```bash
$ vagrant box add centos65 http://www.lyricalsoftware.com/downloads/centos65.box
```

適当なディレクトリで今回使うファイル一式をcloneします。
`vagrant up`ですべてのサーバーが起動し、MySQL、mysql-master-haのインストールが行われます。
4台すべてのセットアップが終わるまで待ちます。

```bash
$ git clone https://github.com/hakuro/vagrant-mysql-ha.git
$ cd vagrant-mysql-ha
$ vagrant up
```

# レプリケーション設定

## my.cnfの設定

MySQL5.6には準同期のレプリケーションがありますが、今回は特に設定を行いません。
MySQLのマスター、スレーブ2台それぞれの`my.cnf`に`server_id`と`log-bin`の設定を追加します。

```bash
$ vagrant ssh mysql_master
$ sudo tee -a /etc/my.cnf <<EOT
[mysqld]
server_id=10
log-bin=mysql-bin
sync_binlog=1
EOT
$ sudo service mysqld restart
$ exit

$ vagrant ssh mysql_slave1
$ sudo tee -a /etc/my.cnf <<EOT
[mysqld]
server_id=11
log-bin=mysql-bin
sync_binlog=1
EOT
$ sudo service mysqld restart
$ exit

$ vagrant ssh mysql_slave2
$ sudo tee -a /etc/my.cnf <<EOT
[mysqld]
server_id=12
log-bin=mysql-bin
sync_binlog=1
EOT
$ sudo service mysqld restart
$ exit
```

（以降、`vagrant ssh`は省略。マスター上の操作は「on master」、スレーブ上の操作は「on slave」、HAマネージャ上の操作は「on manager」と記載する）

## レプリケーション用ユーザの作成

レプリケーション用のユーザを作成します。
on master and slave

```bash
$ mysql -u root -p
mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%' IDENTIFIED BY 'repl';
```

## マスターのバイナリログのファイル名とポジションの確認

マスターのバイナリログのファイル名とポジションを表示させ、FileとPositionをメモしておきます。
通常はマスターをバックアップし、スレーブに適用する必要がありますが、セットアップ直後なので必要ないです。
on master

```bash
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.XXXXXX |      YYY |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
```



## スレーブをマスターに接続

メモしたバイナリログのファイル名とポジションを以下の「mysql-bin.XXXXXX」、「YYY」に当てはめて実行する。
その後、レプリケーションを開始する。
on slave

```bash
$ mysql -u root -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.50.10', MASTER_USER='repl', MASTER_PASSWORD='repl', MASTER_LOG_FILE='mysql-bin.XXXXXX', MASTER_LOG_POS=YYY;
mysql> start slave;
mysql> show slave status\G
```

Slave_IO_Running、Slave_SQL_Runningが「YES」になっていること。
問題なければスレーブをread_onlyにしておきます。
on slave

```bash
mysql> SET GLOBAL read_only = 1;
```

## マスターにVIPを付与する

マスターがフェイルオーバーした前後でアプリケーションがアクセスすべきIPは変化しない必要があります。
マスターのサーバーに仮想IPを付与することで、これを解決します。
フェイルオーバー時には新たなマスターになったスレーブにこの仮想IPが付与されます。
on master

```bash
$ sudo ifconfig eth1:1 192.168.50.100
$ ifconfig
```

# mysql-master-haの設定

## MySQLのrootユーザに他のサーバーからログインできるようにする

そのままの設定ではMySQLが動作しているサーバー以外からrootユーザにログインできないため、ログインできるように設定します。
ログイン元のIPを制限しないのはセキュリティ的に問題がありますが、今回は手元の仮想環境なので特に制限しません。
on master

```bash
$ mysql -u root -p
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
```

## sshの公開鍵認証

各DBサーバー間で相互に公開鍵ログインできるようにし、mysqlユーザがパスワードなしでsudoできるようにします。
on master and slave

```bash
$ sudo usermod -G wheel mysql
$ sudo su - mysql
$ ssh-keygen -b 1024 -t rsa
$ cat ~/.ssh/id_rsa.pub | sudo tee -a /vagrant/authorized_keys
```

HAマネージャのサーバーにはmysqlユーザがいないのでvagrantユーザが公開鍵でログインできるようにします。
on manager

```bash
$ ssh-keygen -b 1024 -t rsa
$ cat ~/.ssh/id_rsa.pub | sudo tee -a /vagrant/authorized_keys
```

各サーバの公開鍵が`/vagrant/authorized_keys`にそろったので、これを`$HOME/.ssh`以下にコピーし、パーミッションの設定をします。
on master and slave

```bash
$ sudo cp /vagrant/authorized_keys /var/lib/mysql/.ssh/authorized_keys
$ sudo chown mysql:mysql /var/lib/mysql/.ssh/authorized_keys
$ sudo chmod 700 /var/lib/mysql/.ssh/authorized_keys
```

on manager

```bash
$ sudo cp /vagrant/authorized_keys /home/vagrant/.ssh/authorized_keys
$ sudo chown vagrant:vagrant /home/vagrant/.ssh/authorized_keys
$ sudo chmod 700 /home/vagrant/.ssh/authorized_keys
```

## mysql-master-haの設定

DBサーバー上にmha用の作業ディレクトリも作っておきます。
on master and slave

```bash
$ sudo mkdir -p /var/log/masterha/app1
$ sudo chown -R mysql:mysql /var/log/masterha
```

HAマネージャのサーバーの設定をします。
mha用の作業ディレクトリを作成し、フェイルオーバー時にVIP等の張り替えをするperlスクリプトを配置し、mysql-master-haの設定ファイルも配置します。
on manager

```bash
$ sudo mkdir -p /var/log/masterha/app1
$ sudo chown -R vagrant:vagrant /var/log/masterha
$ sudo cp /vagrant/mha/master_ip_failover /usr/local/bin/master_ip_failover
$ sudo chmod 755 /usr/local/bin/master_ip_failover

$ sudo touch /etc/masterha_default.cnf
$ sudo mkdir -p /etc/masterha
$ sudo tee -a /etc/masterha/app1.cnf <<EOT
[server default]
user=root
password=root
ssh_user=mysql
manager_log=/var/log/masterha/app1/manager.log
manager_workdir=/var/log/masterha/app1
remote_workdir=/var/log/masterha/app1

repl_user=repl
repl_password=repl

master_ip_failover_script=/usr/local/bin/master_ip_failover

[server1]
hostname=192.168.50.10

[server2]
hostname=192.168.50.11
candidate_master=1

[server3]
hostname=192.168.50.12
no_master=1

EOT
```

## 動作チェッック

sshの疎通、レプリケーションをチェックします。
on manager

```bash
$ masterha_check_ssh --conf=/etc/masterha/app1.cnf
$ masterha_check_repl --conf=/etc/masterha/app1.cnf
```

## マネージャの起動

バックグラウンドで起動します。
on manager

```bash
$ nohup masterha_manager --conf=/etc/masterha/app1.cnf < /dev/null >> /var/log/masterha/app1/console.log 2>&1 &
```

あとはマスター上のMySQLを落としてみるなりして、マスター、スレーブが切り替わるか試してみましょう。