備忘録、はじめました。

作業したこと忘れないようにメモっておきます。

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の準備

oraclemysql: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を起動するスクリプト準備

起動スクリプトの内容は、

  1. dockerコンテナを立ち上げる
  2. レプリケーションの設定
  3. 初期データベースの投入

の流れになります。各ステップの動作を追って見ていきます。

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環境変数oraclemysqlコンテナで設定されている環境変数です。詳細についてはここの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_FILEMASTER_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

Dockerでmysqlサーバコンテナへ別のコンテナからアクセスする | もふもふ技術部