サーバー二台でdocker + MySQLを用いてレプリケーション

ラズパイをサーバー化して環境構築をしているのですが、大苦戦中です。
CPUのアーキテクチャが組込用なので便利なdocker imageが全然使えないという。。。
SSL認証のときも大変でしたが、それはまた別の記事で。


※今回はラズパイをDBサーバーとしましたが、通常のオンプレサーバーであっても同じ書き方でできるはずです。



<h1>1.やりたいこと</h1>
<h2>1.1.レプリケーション</h2>
サーバー１にマスターDBをおき、サーバー２にスレイブDBをおいて、スレイブでマスターDBの更新を検知して全くDBを保持すること
片方のサーバーが物理的に壊れてもDBのデータは残ります。（うっかりdrop tableなんてオペミスは無理ですが）

<h2>1.2.レプリケーションの設定をdockerで簡略化</h2>
結構めんどくさいので、新しいサーバーにもdocker-compose up -dの１コマンドで環境を設定できたら楽です


<h1>2.手順</h1>

<h2>2.1.全体の構成</h2>

サーバー構成
192.168.0.2 → master用サーバー
192.168.0.3 → slave用サーバー

ディレクトリ構成

├── db
│   ├── Dockerfile
│   ├── conf
│   │   ├── master.cnf
│   │   └── slave.cnf
│   └── sql
│       ├── init_master.sql
│       └── init_slave.sql
├── docker-compose.yml


↑treeコマンドで表示したのですが、みづらいですねすみません。


<h2>2.2.docker-compose.ymlの作成</h2>

docker-compose.ymlにてdbディレクトリをビルドします
そしてdbディレクトリには必要な設定ファイルを仕込むのですが、まずはdocker-composeだけ載せますと


```yml:docker-compose.yml
version: '3'

services:
  db:
    build: ./db
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: db_name
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      TZ: 'Asia/Tokyo'。
    volumes:
      # 初期データを投入するSQLが格納されているdir
      - ./db/sql:/docker-entrypoint-initdb.d
      # 永続化するときにマウントするdir
      - /var/lib/mysql:/var/lib/mysql

```

build: ./dbにてdocker-compose.ymlと同じ階層のdbディレクトリをビルドしています。

<h2>2.3.dockerfileとconfigファイルの作成</h2>

次にdockerfileを書きます。
これは一部、マスターとスレーブで書き換えが要ります

```Dockerfile:Dockerfile
FROM mysql:5.7
# 読み込むconfファイルをマスターかスレーブかでコメントアウトして分岐させる
#ENV conf_file ./conf/slave.cnf
ENV conf_file ./conf/master.cnf

ADD $conf_file /etc/mysql/my.cnf
RUN chmod 644 /etc/mysql/my.cnf
```




これまではほとんどmasterとslaveで個別の設定はありませんでした。

次にmasterとslaveのそれぞれのconfファイルを設定していきます。

```master.conf
[mysqld]
user=mysql
server-id = 1
log-bin
binlog-format = MIXED
```

```slave.conf
[mysqld]
user=mysql
server-id=2
log-bin
read_only
```


<h2>2.4.DB初期化時に読み込まれるファイルの作成</h2>

次にdbディレクトリがビルドされるときの初期化のsqlを書きます

```sql:init_master.sql
-- slaveが使用するユーザーを設定(slaveのサーバーの内部IPに合わせる)
CREATE USER 'replica'@'192.168.0.3' IDENTIFIED BY 'replica';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.0.3';
```

```sql:init_slave.sql
-- MASTER_LOG_FILEやMASTER_LOG_POSの調べ方は後述
CHANGE MASTER TO MASTER_HOST='192.168.0.2', 
    MASTER_PORT=3306, 
    MASTER_USER='replica', 
    MASTER_PASSWORD='replica', 
    MASTER_LOG_FILE='3ae7abcabc-bin.000003', 
    MASTER_LOG_POS=1234;
```


init_slave.sqlのmaster_log_fileやmaster_log_posの調べ方ですが、マスターDBサーバーのコンテナに入って

```
$docker exec -it <container_id> bash
#mysql -u root -p password
>show master status\G;
```

こんな順番でコマンドを入力するとマスターのログファイルの位置が取得できます。
mysql 5.7以降だったか、わざわざこんなことをしなくても　
MASTER_AUTO_POSITION=1
と設定するだけでいけるとかなんとか

これでレプリケーションできるかと思います。

何もミスってなければslaveのサーバーにて

```
$docker exec -it <container_id> bash
#mysql -u root -p password
>show slave status\G;
```

こんな感じでDBコンテナに入ってコマンドを打つとずらーっと表示されますが

```
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
```

この２つのパラメータがYesになります
connectingとか書いてたらだめです。

ずらーっと表示されている下の方にエラー内容が出ます

```
Last_IO_Errno: 0
Last_IO_Error: 
Last_SQL_Errno: 0
Last_SQL_Error: 
```

※これは正常な状態です

ここに出てくるエラーナンバーやエラーメッセージを頼りにデバッグしたらできるかと思います。

どうしても自動化しきれていませんが、だいぶ再現するのが楽にはできたかなと思います。
何か補足があったらぜひお願いいたします。

あ、あと既にテーブルがあって運用中のDBをマスタースレーブ構成にしたい場合は、masterでダンプしてそのデータをslaveでリストアして反映する必要があります。

https://qiita.com/marienplatz/items/3255b2d7f7f922ab115a

こっちに書きましたので参考までに


参考
http://www.tohoho-web.com/ex/mysql-replication.html