Docker上でMySQLレプリケーション環境構築

# 背景
- フレームワークを自作する夢はある
- Laravelは美しくシンプルなライブラリをいっぱい取り入れている
- Laravel採用した優秀なライブラリをすべて単体で使ってみる
- 今回はORMライブラリのEloquentを使ってみる
- まずはEloquentのmasterとslaveを切り替えを実現したい
- Docker上でMySQLレプリケーション環境を構築する必要がある（本編）

# 前提
- レプリケーション用専用ネットワークを構築する
- MySQLデータの永続化

# サーバー構成

```
192.168.0.11 → master用サーバー
192.168.0.12 → slave用サーバー
```

# ディレクトリ構成

```
├── docker
│   └── db
│       ├── init
│       │   ├── 001_schema.sql
│       │   ├── 002_sample.sql
│       │   └── start-slave.sh
│       ├── master.cnf
│       └── slave.cnf
└── docker-compose.yml
```

# master.cnf
```
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
expire_logs_days=5
log-bin=mysql-bin
server-id=200
```

# slave.cnf
```
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
expire_logs_days=5
server-id=201
read_only=1
```

# start-slave.sh
```
#!/bin/sh

# masterをロック
mysql -u root -h master -e "RESET MASTER;"
mysql -u root -h master -e "FLUSH TABLES WITH READ LOCK;"

# master情報をdump
mysqldump -u root -h master --all-databases --master-data --single-transaction --flush-logs --events > /tmp/master_dump.sql

# slaveにimport
mysql -u root -e "STOP SLAVE;";
mysql -u root < /tmp/master_dump.sql

# bin-logのファイル名とポジションを取得
log_file=`mysql -u root -h master -e "SHOW MASTER STATUS\G" | grep File: | awk '{print $2}'`
pos=`mysql -u root -h master -e "SHOW MASTER STATUS\G" | grep Position: | awk '{print $2}'`

# slave開始
mysql -u root -e "RESET SLAVE;";
mysql -u root -e "CHANGE MASTER TO MASTER_HOST='master', MASTER_USER='repl', MASTER_PASSWORD='Zaq1Zaq1', MASTER_LOG_FILE='${log_file}', MASTER_LOG_POS=${pos};"
mysql -u root -e "START SLAVE;"

# masterをunlockする
mysql -u root -h master -e "UNLOCK TABLES;"
```

# 001_schema.sql

```
CREATE USER 'repl'@'192.168.0.12' IDENTIFIED BY 'Zaq1Zaq1';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.0.12';
FLUSH PRIVILEGES;

DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'タイトル',
  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='ブログ';

```
※ slaveサーバーのip_addressを指定すること
※ レプリケーション用ユーザー名情報を指定すること

# docker-compose.yml

```
version: '3'

services:
  master:
    container_name: blog-db-master
    image: mysql:5.7
    ports:
      - "63306:3306"
    volumes:
      - blog-data:/var/lib/mysql # masterはvolumeをmount(永続化させる)
      - ./docker/db/master.cnf:/etc/mysql/conf.d/master.cnf
    networks:
      blog_network:
        ipv4_address: 192.168.0.11
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
      - MYSQL_DATABASE=db_blog
      - MYSQL_USER=db_blog
      - MYSQL_PASSWORD=Zaq1Zaq1
      - TZ=Asia/Tokyo
  slave:
    container_name: blog-db-slave
    image: mysql:5.7
    ports:
      - '63307:3306'
    depends_on:
      - master
    tmpfs: /var/lib/mysql
    volumes:
      - ./docker/db/slave.cnf:/etc/mysql/conf.d/slave.cnf
      - ./docker/db/init/start-slave.sh:/docker-entrypoint-initdb.d/start-slave.sh
    networks:
      blog_network:
        ipv4_address: 192.168.0.12
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
      - MYSQL_DATABASE=db_blog
      - MYSQL_USER=db_blog
      - MYSQL_PASSWORD=Zaq1Zaq1
      - TZ=Asia/Tokyo
volumes:
  blog-data:
    driver: 'local'

networks:
  blog_network:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.0.0/24

```

# 初回
```
docker-compose build
docker-compose up master
docker exec -i blog-db-master mysql -r db_blog < docker/db/init/001_schema.sql
docker exec -i blog-db-master mysql -r db_blog < docker/db/init/002_sample.sql
docker-compose up slave
docker-compose stop
docker-compose up -d
```

```
Pool overlaps with other one on this address space
```
上記のエラー出る場合は、ip_address空間や、ホストのip_address空間と重複している可能性があるので、
docker-compose.ymlに指定した「networks:」の「subnet」を違うアドレスに変更してみてください。

# 次回以降
```
docker-compose up -d
```

参考
https://qiita.com/takyam/items/f13bc4a1db0433ffb958
https://qiita.com/Butterthon/items/e85825d3eff6559a1cf1

ソースコードはこちら
https://github.com/horityabiriko/docker-mysql-replication