🍣

ComposeでサクッとMySQLのレプリケーションを試す

に公開

前提

Docker ComposeでMySQLのレプリケーションを試します。マスタ1、スレーブ1のシンプルな構成です。

Docerfileの作成

今回の本質ではないので日本語対応が必要ない方はスキップしていただいて構いません。スキップした場合はdocker-compose.yamlで直接mysqlの公式イメージを使用してください。

FROM mysql:8.0

RUN microdnf update -y \
    && microdnf install -y glibc-locale-source bash \
    && localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8

ENV LANG=ja_JP.UTF-8
ENV LC_ALL=ja_JP.UTF-8

テーブル作成用のsqlと初期設定用のシェルスクリプトを準備する

マスタで使用する、テーブル作成用のsqlを作成します。

CREATE DATABASE IF NOT EXISTS app;

USE app;

CREATE TABLE IF NOT EXISTS sample_table (
    id INT AUTO_INCREMENT PRIMARY KEY,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

マスタで使用する、レプリケーション用ユーザを設定するシェルスクリプト作成します。環境変数を使用したいためsqlではなくシェルスクリプトを使用することにします。

mysql -u root -p$MYSQL_ROOT_PASSWORD -e "CREATE USER '$REPLICA_USER'@'%' IDENTIFIED BY '$REPLICA_PASSWORD';"
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "GRANT REPLICATION SLAVE ON *.* TO '$REPLICA_USER'@'%';"
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "FLUSH PRIVILEGES;"

スレーブで使用する、初期設定用のシェルスクリプトを作成します。
はじめに、CHANGE REPLICATION SOURCE TOでマスタを指定します。MySQL 8.0.23以降ではCHANGE MASTER TOは非推奨となりました。
https://dev.mysql.com/doc/refman/8.0/ja/change-master-to.html

次にマスタのデータをダンプし、スレーブ側で読み込みます。--master-data=1を指定することでSOURCE_LOG_FILE (MASTER_LOG_FILE)SOURCE_LOG_POS (MASTER_LOG_POS)を手動で指定する必要がなくなります。

最後にSTART REPLICAでレプリケーションを開始します。こちらもMySQL 8.0.22からSTART SLAVEが非推奨になりました。
https://dev.mysql.com/doc/refman/8.0/ja/start-slave.html

echo "Starting the MySQL slave initialization script..."

# Execute the command to set up the slave
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "CHANGE REPLICATION SOURCE TO SOURCE_HOST='$MASTER_HOST', SOURCE_PORT=$MASTER_PORT, SOURCE_USER='$REPLICA_USER', SOURCE_PASSWORD='$REPLICA_PASSWORD', GET_MASTER_PUBLIC_KEY=1;"
if [ $? -ne 0 ]; then
    echo "Error: Unable to set up the slave server."
    exit 1
fi
echo "Successfully set up the slave server."

# Dump the master database
mysqldump -u $MASTER_USER -h $MASTER_HOST -P $MASTER_PORT -p$MASTER_PASSWORD --all-databases --single-transaction --routines --triggers --events --master-data=1 > /tmp/master_dump.sql
if [ $? -ne 0 ]; then
    echo "Error: Unable to dump the master database."
    exit 1
fi
echo "Successfully dumped the master database."

# Import the dump into the slave
mysql -u root -p$MYSQL_ROOT_PASSWORD < /tmp/master_dump.sql
if [ $? -ne 0 ]; then
    echo "Error: Unable to import the dump into the slave."
    exit 1
fi
echo "Successfully imported the dump into the slave."
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "START REPLICA;"
if [ $? -ne 0 ]; then
    echo "Error: Unable to start the slave."
    exit 1
fi
echo "Successfully started the slave server."

docker-compose.yamlの設定

上記の各種設定ファイルを使用するようdocker-compose.yamlを構成します。一部省略している箇所があります。スレーブはマスタのヘルスチェックが通ることを確認してから起動するよう設定しておきます。

services:
  db-master:
    container_name: ${COMPOSE_PROJECT_NAME}_master
    build:
      context: ./mysql
      dockerfile: Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: password
      ...
    volumes:
      - ./mysql/master/init:/docker-entrypoint-initdb.d
      - ./mysql/master/conf.d:/etc/mysql/conf.d
      - ./volume/master/mysql:/var/lib/mysql
      - ./volume/master/log/mysql:/var/log/mysql
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD" ]
      interval: 5s
      timeout: 30s
      retries: 10
      start_period: 120s
  db-slave:
    container_name: ${COMPOSE_PROJECT_NAME}_slave
    build:
      ...
    environment:
      ...
    depends_on:
      db-master:
        condition: service_healthy
    volumes:
      ...
    healthcheck:
      ...

動作を試す

マスタにクエリを発行したのち、スレーブでもデータが正しく反映されていることを確認します。

まとめ

今回使用したコードは以下で公開しています。
https://github.com/koukiito/mysql-replication-hands-on

フォロー、X(Twitter)フォローもよろしくお願いいたします。
https://twitter.com/kouki__ito

Discussion