Dockerで手元にmysqlレプリケーション環境を構築
はじめに
手元でレプリケーションの挙動とか、遅延の再現や復旧方法を見直したい場合などに手軽に実験や確認できる環境が欲しい。 Vagrantとかで一つ一つインスタンス立ち上げるのもヘビーなのでdockerで構成させたい、といった理由で作ってみました。
TL;DR
実施内容
前準備
前準備として、
- dockerのインストール
をしておきます。また、masterとslaveのDockerfileを分けたいので、以下のように階層構造を作ります。
├── master │ ├── Dockerfile │ ├── my-master.cnf │ └── start-master.sh ├── README.md ├── slave1 │ ├── Dockerfile │ ├── my-slave.cnf │ └── start-slave1.sh └── ...
Dockerfileの準備
oracleのmysql:5.5のdockerイメージをベースで作りました。
masterのDockerfile:
# Docker mysql-master FROM mysql:5.5 MAINTAINER tkyshm ADD my-master.cnf /etc/mysql/conf.d RUN mkdir -p /var/log/mysql RUN touch /var/log/mysql/mysql-bin.log RUN chown -R mysql:mysql /var/log/mysql EXPOSE 3306 CMD ["mysqld"]
slaveのDockerfile:
# Docker mysql-master FROM mysql:5.5 MAINTAINER tkyshm # ADDだけmasterと違う ADD my-slave.cnf /etc/mysql/conf.d RUN mkdir -p /var/log/mysql RUN touch /var/log/mysql/mysql-bin.log RUN chown -R mysql:mysql /var/log/mysql EXPOSE 3306 CMD ["mysqld"]
masterとslaveの違いは追加するcnfのファイルだけとなります。 次にmysqlのconfファイルの設定です。
mysqlのconfファイル
masterとslaveに追加するconfは以下になります。
- my-master.cnf
[mysqld] server-id = 1 log_bin = /var/log/mysql/mysql-bin.log
- my-slave.cnf
[mysqld] server-id = 2 log_bin = /var/log/mysql/mysql-bin.log
※ server-idは一意な値にする必要が有ります。
Dockerイメージのbuild
以下、buildします。
$ cd master $ docker build -t mysql-master:0.1 . $ cd ../slave1 $ docker build -t mysql-slave1:0.1 .
masterとslaveを起動するスクリプト準備
起動スクリプトの内容は、
- dockerコンテナを立ち上げる
- レプリケーションの設定
- 初期データベースの投入
の流れになります。各ステップの動作を追って見ていきます。
dockerコンテナを立ち上げる
以下コマンドでmasterとslaveのコンテナを立ち上げます。
- master起動:
$ docker run --name mysql-master -e MYSQL_ALLOW_EMPTY_PASSWORD=true -p 13306:3306 -d mysql-master:0.1
masterの起動はホストのport番号13306を介してmysqlサーバーに接続します。そのため、Dockerのホストからmasterのmysqlに接続したい場合はホストを127.0.0.1を指定し、ポートは13306を指定します。
MYSQL_ALLOW_EMPTY_PASSWORD
の環境変数はoracleのmysqlコンテナで設定されている環境変数です。詳細についてはここのEnvironment Variablesに記載されています。
slaveの起動も同様に起動します。
- slave起動:
$ docker run --name mysql-master -e MYSQL_ALLOW_EMPTY_PASSWORD=true -p 13306:3306 -d mysql-master:0.1
レプリケーションの設定
レプリケーションするためのユーザを作っておきます。既存ユーザでも可能ですが、master.infoのファイル内にユーザ名とパスワードがテキストで保存されるので、安全性を考慮してレプリケーション権限のあるユーザを作成するのが良いらしいです(手元でやるだけなので不要かも)。
- master
$ mysql -u root -h 127.0.0.1 -P 13306 -e "GRANT REPLICATION SLAVE ON *.* TO 'repli'@'172.17.0.%' IDENTIFIED BY 'repli';" $ mysql -u root -h 127.0.0.1 -P 13306 -e "flush privileges;"
- slave
$ mysql -u root -h 127.0.0.1 -P 13316 -e "GRANT REPLICATION SLAVE ON *.* TO 'repli'@'172.17.0.%' IDENTIFIED BY 'repli';" $ mysql -u root -h 127.0.0.1 -P 13316 -e "flush privileges;"
master側でbinログの状態を確認します。
$ mysql -u root -h 127.0.0.1 -P 13306 -e "show master status\G"
上記の出力結果のFileとPositionの値はslave側でmasterが誰かを設定するときに使います。
次に、slave側でmasterが誰なのかを設定します。設定後はslaveを開始します。
$ mysql -u root -h 127.0.0.1 -P 13316 -e "CHANGE MASTER TO MASTER_HOST='172.17.0.2', MASTER_USER='repli', MASTER_PASSWORD='repli', MASTER_LOG_FILE='mysql-bin.0001', MASTER_LOG_POS=0;" $ mysql -u root -h 127.0.0.1 -P 13316 -e "start slave;" $ mysql -u root -h 127.0.0.1 -P 13316 -e "show slave status\G"
## 上記最初のコマンドのslaveにmasterを教えるsqlをワンライナーだと見辛いので見やすくした. CHANGE MASTER TO MASTER_HOST='172.17.0.2', MASTER_USER='repli', MASTER_PASSWORD='repli', MASTER_LOG_FILE='mysql-bin.0001', MASTER_LOG_POS=0;
MASTER_HOST
はmasterのipを入れます。ipはdockerコンテナ内だと通常172.17.0.*のアドレスが割り当てられるので、その値が入ります。取得方法はinsepctを用います。
$ docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql-master
show master status\G
で確認したFileとPositionは、MASTER_LOG_FILE
とMASTER_LOG_POS
に値が入ります。
以下、スクリプトでまとめちゃいます。
- start-master.sh
#!/bin/bash master_host=127.0.0.1 docker run --name mysql-master -e MYSQL_ALLOW_EMPTY_PASSWORD=true -p 13306:3306 -d mysql-master:0.1 sleep 10 # master setup mysql -u root -h 127.0.0.1 -P 13306 -e "GRANT REPLICATION SLAVE ON *.* TO 'repli'@'172.17.0.%' IDENTIFIED BY 'repli';" mysql -u root -h 127.0.0.1 -P 13306 -e "flush privileges;"
- start-slave.sh
#!/bin/bash docker run --name mysql-slave1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true -p 13316:3306 -d mysql-slave1:0.1 sleep 10 mysql -u root -h 127.0.0.1 -P 13316 -e "GRANT REPLICATION SLAVE ON *.* TO 'repli'@'172.17.0.%' IDENTIFIED BY 'repli';" mysql -u root -h 127.0.0.1 -P 13316 -e "flush privileges;" # slaveでのmaster設定 master_port=13306 file=$(mysql -u root -h 127.0.0.1 -P $master_port -e "show master status\G" | grep File | awk '{print $2}') position=$(mysql -u root -h 127.0.0.1 -P $master_port -e "show master status\G" | grep Position | awk '{print $2}') master_host=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql-master` mysql -u root -h 127.0.0.1 -P 13316 -e "CHANGE MASTER TO MASTER_HOST='$master_host', MASTER_USER='repli', MASTER_PASSWORD='repli', MASTER_LOG_FILE='$file', MASTER_LOG_POS=$position;" mysql -u root -h 127.0.0.1 -P 13316 -e "start slave"
初期データベースの投入
初期のデータベースの投入は試したい環境に応じて適宜処理していく流れとなるかと思います。例えば、create databaseして用意したsqlファイルを流し込む、といった処理になるかと思います。
レプリケーションの確認
あとは、レプリケーションが正常に動作しているかを確認するだけになります。masterのデータベースの任意のテーブルに何かレコードを挿入し、slave側でレプリケーションされるか確認します。
まとめ
手元で気軽にレプリケーションの動作等の確認をするための環境が欲しくて作ってみました。環境はdockerコンテナで構築しました。
今後は他のミドルウェアとmysqlの連携も確認できるようにしたいので、その辺りの手元コンテナ化をやっていきたい気持ちだけあります。
サンプルも用意してあります。サンプル
参考URL