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.log
に MySQL のログが残るので、 tail
, less
などを利用してログを見ることで、レプリケーションがうまくいっているか確認したい
Links
- MySQL :: MySQL 5.7 Reference Manual :: 16 Replication
- MySQL :: MySQL 5.7 Reference Manual :: 16.2.1 Replication Formats
- MySQL :: MySQL 5.7 Reference Manual :: 16.1.2.4 Choosing a Method for Data Snapshots
- MySQL :: MySQL 5.7 Reference Manual :: 13.7.5.34 SHOW SLAVE STATUS Syntax
- library/ubuntu - Docker Hub
- dockerのlinkオプションがレガシーなので、コンテナ間で名前解決できるようにネットワークを用意する - Qiita
- Legacy container links | Docker Documentation
- Docker container networking | Docker Documentation
- ユーザ権限の確認・追加 - Qiita