dockerでmysqlのマスター・スレーブ構成をつくるにはどうすればいいのか気になったので実際に作ってみることにした。
###そもそもどうやってレプリケーションは行われるのか?
まず、最低限必要な設定は以下の項目です。
masterと各slaveがそれぞれ異なるserver-idを持っていること
[master]バイナリログが有効となっていること
[master]スレーブのIOスレッドが接続するためのREPLICATIONSLAVE権限を持つユーザが存在すること
[slave]IOスレッドがCHANGE MASTER TOコマンドで指定するマスターに接続可能であること
この図解では、GTIDに基づくレプリケーションの場合の流れを説明している。
GTIDとは、server_id:taransaction_id
の組み合わせで、これをmasterのbinaryLogに書き込み、slaveのrelayLogに転送する。slave側ではこのGTIDに基づいて読み込み済みかそうでないかを判別する。そうでない場合にslaveのmysqlに書き込まれる。
GTIDベースのレプリケーションを行う場合は、MASTER_AUTO_POSITION = 1
をCHANGE MASTER TOコマンドで指定する。
今後、説明する内容は、GTIDベースのレプリケーションを行う場合の設定である。
###1,実際のdocker-composeとDockerfileの設定
slave側で、masterと同じ名前でアカウントを作るようにenvironment
で指定したりすると、レプリケーション時にうまくいかなかったりしたので注意。
version: '3'
services:
master_mysql:
build: ./mysql/master
container_name: 'master_mysql'
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: master_database
MYSQL_USER: ken3pei
MYSQL_PASSWORD: pass
volumes:
# 初期データを投入するSQLが格納されているdir
- ./db/sql/master:/docker-entrypoint-initdb.d
# 永続化するときにマウントするdir
- ./mysql/master/volumes:/var/lib/mysql
slave_mysql:
build: ./mysql/slave
container_name: 'slave_mysql'
ports:
- "6612:3306"
environment:
MYSQL_ROOT_PASSWORD: pass
volumes:
- ./db/sql/slave:/docker-entrypoint-initdb.d
- ./mysql/slave/volumes:/var/lib/mysql
depends_on:
- master_mysql
php:
build: ./php
ports:
- '80:80'
volumes:
- ./php:/var/www/html
# master側
FROM mysql:5.7
COPY ./master.cnf /etc/mysql/conf.d/
# slave側
FROM mysql:5.7
COPY ./slave.cnf /etc/mysql/conf.d/
###2,build時に実行するSQLファイル
・replicaユーザーのホストを%にしているのは、IPアドレスか%でしかレプリケーションが成功しなかったからです。本当はコンテナ名で名前解決したかったのですができませんでした。(なぜ...)
・注:CHANGE MASTER TOコマンドは、START SLAVE
状態では使えないので、間違えて打ち直す場合などは、STOP SLAVE
コマンドでレプリケーションを停止してからにしましょう。
・IPアドレスを指定する場合は、hostname -i
コマンドをマスター側コンテナで打ち、IPアドレスを確認して以下のsql文の%と置き換えればOKです。
・きちんとユーザーが創られているかは、mysql> select user, host from mysql.user;
コマンドで確認できる。
CREATE USER 'replica'@'%' IDENTIFIED BY 'replica';
GRANT REPLICATION SLAVE ON *.* TO 'replica'@'%';
CHANGE MASTER TO MASTER_HOST='master_mysql',
MASTER_PORT=3306,
MASTER_USER='replica',
MASTER_PASSWORD='replica',
MASTER_AUTO_POSITION = 1;
START SLAVE;
###3,master/slaveそれぞれの設定ファイル
・server-idでそれぞれ一意なidをもたせている。
・log-binによって、master側のbinaryLogを有効にしなければレプリケーションはできない。slave側で、log-binを指定しなくともレプリケーションはできるが、有効にすることでデータバックアップとクラッシュリカバリに利用できる。
・最初はgtid-mode=ON
を指定するだけだと、「enforce-gtid-consistencyをONにしてから行いなさい」といった内容のエラーが出た。なのでenforce-gtid-consistencyを追加した。
・実は、read_only
指定だとroot権限による書き込みは制御できない。そのためroot権限による書き込みも禁止したければ、Mysql5.7以降に追加された、super_read_only=1
オプションを指定すればいい
・これら設定が反映されているかは、mysql> SHOW VARIABLES;
コマンドを叩いて確認できる。
[mysqld]
server-id = 1
log-bin
enforce-gtid-consistency=ON
gtid-mode=ON
[mysqld]
server-id = 2
log-bin
enforce-gtid-consistency=ON
gtid-mode=ON
read_only
###4,実際のディレクトリ構成
###5,レプリケーションができているか確認する。
・上記のように設定できたらdocker-compose up
などでビルドして確認する。
・slave側のコンテナに入り、さらにmysqlサーバーに入る。そこで以下のコマンドを入力。するとズラッと結果がでてくるので、そのなかのSlave_IO_RunningとSlave_SQL_RunningがYESになっていたらOK!
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: master_mysql
Master_User: replica
Master_Port: 3306
・・・・・
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
・・・・・
・・・・・
なにもしなくても、Master側で作るように指定したmaster_databaseというDBが反映されている。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| master_database |
| mysql |
| performance_schema |
| sys |
+--------------------+
参考にしたサイト
https://dev.mysql.com/doc/refman/5.6/ja/replication-howto-masterbaseconfig.html
https://qiita.com/marienplatz/items/f5b544a29353bc0ad409
https://www.seeds-std.co.jp/blog/creators/2020-12-17-145757/