ブログ

読んで思い出す。忘れるために書く

MySQL で master/slave レプリケーションを構成してみる(Docker)

Docker を絡めた操作をしてて難しそうに見えるけれど、やっていることは単純で、2台のサーバをMySQL サーバとして master/slave 構成になるように設定しているだけ

まとめ

MySQLレプリケーションについて調べてみて、2つの Docker コンテナを立ち上げて master/slave レプリケーションを実現する方法を書いた

ここでのレプリケーションは本当に基礎的な部分だけで、メリットやデメリット、より複雑な構成については言及していない

詳しくは MySQL のドキュメントを参照したい

これをすると何が嬉しいか

よくわからない

この単純な構成であっても: 書き込みは master に任せて、アプリケーションからのDB 読み出しアクセスは slave に任せられるので、書き込み・読み出しの分担により負荷軽減・高速読み出しが期待できる

たとえ master が完全に沈黙しても、slave 側から dump を採って復旧できる可能性が残された状態を保てる

master の仕事を邪魔せずに、 slave 側にアクセスしてデータ分析のクエリを投げる、といったこともできるかもしれない

前提

この記事で言及しないこと

  • Docker コンテナを commit して保存する方法
  • commit したコンテナを立ち上げと同時に コンテナ内の MySQL サーバを立ち上げる方法

手順

コンテナの立ち上げ

# これから設定をしていくコンテナ2つを立ち上げ
# * それぞれ MySQL サーバの master/slave 役として利用する
# * コンテナ外から接続できるようポートの関連付けを設定
# * docker コマンドでの操作をわかりやすくするためそれぞれに名前付け
docker container run -d --name master01 -p 4567:3306 -it ubuntu /bin/bash
docker container run -d --name slave01  -p 4568:3306 -it ubuntu /bin/bash

SSH 接続する代わりに、 attach して、コンテナ内でコマンド入力など操作をしていく

# master の設定から開始
docker container attach master01

# 次に slave
docker container attach slave01

コンテナ間のネットワーク接続を確立

(--link オプションは死んだ...!!)

異なるコンテナ間を通信可能にするために、ネットワークを作成して、各コンテナをそこに参加させる

docker network create mysql_net
docker network connect mysql_net master01
docker network connect mysql_net slave01

予めネットワークを作成しておき、コンテナ立ち上げ時に --net オプションで作成したネットワーク名を指定してもいい

ネットワークに参加しているコンテナを確認するには docker network inspect mysql_net という風にコマンドを叩く

( jq コマンドが使える場合は jq .[0].Containers をパイプで繋いであげると分かり易しい)

MySQL とエディタのインストール

# master & slave で実施
# ザツな指定で ver.5.7 系をインストール
apt update && apt install -y --fix-missing mysql*5.7
# 設定ファイルを編集するので なにかエディタをインストール
apt install -y vim

設定ファイルの編集

設定ファイルとディレクトリ・ファイル構成

# 大本の設定ファイルを見てみる
vim -R /etc/mysql/my.cnf

ディレクトリを指定して設定ファイルを一括して読み込んでいるっぽい

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

/etc/mysql/mysql.conf.d/mysqld.cnf が設定例に詳しいので、参考になりそう

設定の追記

設定ファイルの説明を参考に、デフォルト設定を残しつつ、変更したい部分は別ファイルとして記述する

# ファイルのコピーをして、そちらを編集していく
# ファイル名は任意でOK
cd /etc/mysql/mysql.conf.d/

# master 側
cp mysqld.cnf master.cnf
mv mysqld.cnf mysqld # 一部設定が被るので無効化(*.cnf じゃないファイルは読み込まれない)
vim master.cnf

# slave 側
cp mysqld.cnf slave.cnf
vim slave.cnf # slave 側

今回は「binary log file position based replication」でレプリケーションをしたいので、次のように設定を有効化する

# コメントアウトを外す
# server-id は master/slave 間で一意に定められた数値を使用する
server-id               = 1
log_bin                 = /var/log/mysql/mysql-bin.log
# master 側はザツにどこからでも接続を受け付けるよう設定する
bind-address            = 0.0.0.0
# slave 側はどのDB をレプリケーション対象とするか設定する
binlog_do_db            = app

ここでは、レプリケーション対象DB を app にして、 master/slave の server-id をそれぞれ 1 と 2 に設定する

(実際のところは、 select host, user from mysql.user; で確認できるホスト/ユーザの組み合わせからの接続のみを受け付ける)

# サービスの再起動をして設定値を有効化
service mysql restart

Master 側にレプリケーション用ユーザの作成

レプリケーション作業をするために slave からのアクセスを許可したいので、それ用にユーザを新規に作成する

# master 側
# MySQL サーバにアクセス
mysql -u root -p
# user repl を、パスワード(identified by) repl で作成
# レプリケーション、スレーブ権限を付与
CREATE USER 'repl' IDENTIFIED BY 'repl';
GRANT REPLICATION SLAVE ON *.* TO 'repl';

Note: 実際に利用する場合はセキュリティを考慮して、ユーザ名の後ろに @ とホスト名ないし IP アドレスを加えて (eg. 'repl'@'db1.example.com')、「どこからアクセスしてきたユーザか」を明示して、アクセス元制限を加えたい

Slave 側でレプリケーションを有効化

master 側でテーブルのロックを外しておく

mysql -u root -p
unlock tables;

slave 側でレプリケーションを有効化する

mysql -u root -p
# 参照する master への接続設定を加える
# 設定記述の途中で改行してるので「->」が付与されている
mysql> CHANGE MASTER TO
    -> MASTER_HOST='172.17.0.2',
    -> MASTER_PORT=3306,
    -> MASTER_USER='repl',
    -> MASTER_PASSWORD='repl';
start slave; # スレーブとして処理を開始
# SHOW SLAVE STATUS\G で状態確認

データが複製されてるか確認する

データベースとテーブルの作成

# master 側
mysql -u root -p
# データベースとテーブルの作成
CREATE DATABASE app;
USE app;
CREATE TABLE IF NOT EXISTS User (
    id int primary key auto_increment,
    name varchar(255)
) DEFAULT CHARSET=utf8;
# レコードの挿入
INSERT INTO User(name) VALUES("foo");
INSERT INTO User(name) VALUES("bar");

接続とデータの確認

# slave 側
mysql -u root -p
# 試しにデータベース一覧の表示を要求する
show databases
# => app データベースが表示されてるはず
# 使用するデータベースの切り替え
USE app;
# レコードの確認
SELECT * FROM User;
# => master 側で挿入した foo が見えるはず

同様に、 app データベースを対象に、 master 側でテーブルの作成やレコードの挿入をしていくと、slave 側にも反映されているのが確認できると思う

エラーの見方

ここまでで、この記事に何かしら誤りがあったり、あるいは作業ミスがあった場合は、うまくいかないことがあるかもしれない

たとえば今回利用している Ubuntu の場合、 /var/log/mysql/error.logMySQL のログが残るので、 tail, less などを利用してログを見ることで、レプリケーションがうまくいっているか確認したい

Links