alphineLinuxを用いたk8s構築（web/ap/dbサーバ）～MySQLレプリケーション（docker-compose構築）編～

## 目的
AlpineLinux3.17をベースで、MySQLdockerカスタムイメージを構築し、
Kubernetes構築を実施前に、予め以下構成で、レプリケーション構成を構築できるかをテストするのが目的となります。
* MySQL Masterコンテナ（1つ）
* MySQL Slaveコンテナ（1つ）

※今回は、自動フェイルオーバー機能はつけず、純粋にデータが複製できるかの観点を確認します。（今後確認予定です。）

## 構築準備・事前作業
構築観点として、イメージをdocker-composeでビルドし、MySQLのMasterとSlaveのDockerコンテナを起動します。
イメージをビルドする際、MySQLのalpineイメージはないので、
AlpineLinuxのdockerイメージをベースとし、MySQLをインストールします。
初期状態のデータベースでは、レプリケーションは自動開始しないので、
適切な設定(後述)をし、レプリケーションを行います。


* docker-compose.yml
```
version: '3.7'

services:

  master:
    container_name: t_kyn_001_mysql_master
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - ./master/conf/:/conf
      - ./mastersetup.sh:/usr/local/bin/setup.sh
      - ./master_log/:/var/log/mysql/
      - ./master_db:/var/lib/mysql
      - ./master/conf/my.cnf:/etc/my.cnf
    tty: true
    environment:
      TZ: 'Asia/Tokyo'
      MYSQL_USER: 'mysql'
      MYSQL_PASSWORD: '★！秘密！★'
      MYSQL_ROOT_PASSWORD: 'master'
    command: >
      /bin/sh -c "
      cp /conf/my.cnf /etc/ &&
      chmod 644 /etc/my.cnf &&
      chmod 755 /entrypoint.sh &&
      /entrypoint.sh mysqld"
    networks:
      - demo-network

  slave:
    container_name: t_kyn_001_mysql_slave
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - ./slave/conf/:/conf
      - ./slavesetup.sh:/usr/local/bin/setup.sh
      - ./slave_log/:/var/log/mysql/
      - ./slave_db:/var/lib/mysql
      - ./slave/conf/my.cnf:/etc/my.cnf
    tty: true
    environment:
      TZ: 'Asia/Tokyo'
      MYSQL_USER: 'mysql'
      MYSQL_PASSWORD: '★！秘密！★'
      MYSQL_ROOT_PASSWORD: 'slave'
    command: >
      /bin/sh -c "
      cp /conf/my.cnf /etc/ &&
      chmod 644 /etc/my.cnf &&
      chmod 755 /entrypoint.sh &&
      /entrypoint.sh mysqld"
    networks:
      - demo-network

volumes:
  master_db: {}
  master_log: {}
  slave_db: {}
  slave_log: {}

networks:
  demo-network:
    driver: bridge
```

* entrypoint.sh
MySQLコマンドを実行し以下を定義します。
    * データベースのインストールディレクトリ先の指定
    * mysqld_safeで起動し、MySQLポートでの疎通確認
    * MYSQL_ROOT_PASSWDをルートアカウント用のパスワードに設定
    * MySQL再起動反映
    * ログ出力先の権限変更

※「★！秘密！★」のところはMySQLのパスワードなので、参考にする場合は良しなに変更頂ければと思います。
```
#! /bin/sh

mysql_install_db --user=mysql --datadir=/var/lib/mysql

sed -i "s|.*skip-networking.*|#skip-networking|g" /etc/my.cnf.d/mariadb-server.cnf

mysqld_safe --datadir=/var/lib/mysql/ &

nc -zv 0.0.0.0 3306 &> /dev/null
while [[ $? == 1 ]]
do
nc -zv 0.0.0.0 3306 &> /dev/null
done

apk del netcat-openbsd

export MYSQL_ROOT_PASSWD='★！秘密！★'
mysql -e "use mysql;select User, host from mysql.user;grant all privileges on *.* to 'root'@'%' identified by '$MYSQL_ROOT_PASSWD' with grant option;flush privileges;"

mysqladmin shutdown

mysqld_safe --datadir=/var/lib/mysql

chown -R mysql:mysql /var/log/mysql/
chmod 777 /var/log/mysql/
chmod 640 /var/log/mysql/*
```

* mastersetup.sh
Master構成のdockerの/etc/my.cnfに対して、server-idを自動割り振りするスクリプトです。
```
#!/bin/sh

OCTETS=`hostname -i | tr -s '.' ' '`

i=3
set $OCTETS
if [ $i -ge 10 ]
then
 i=`expr $i - 9`
 shift 9
fi
v1="v1=\$$i"
eval $v1

i=4
if [ $i -ge 10 ]
then
 i=`expr $i - 9`
 shift 9
fi
v2="v2=\$$i"
eval $v2

MYSQL_SERVER_ID=`expr $v1 \* 256 + $v2`

sed -i -e "/# START/,/# END/ s/SERVER_ID/$MYSQL_SERVER_ID/g" /etc/my.cnf
sed -i -e '/# START/,/# END/ s/# server_id/server_id/g' /etc/my.cnf
sed -i -e '/# START/,/# END/ s/# log_bin/log_bin/g' /etc/my.cnf
```

* slavesetup.sh
SLAVE構成のdockerの/etc/my.cnfに対して、server-idを自動割り振りするスクリプトです。
mastersetup.shと内容同じなので、分ける必要もなかったのですが、今後自動フェイルオーバの検証も行うことを視野に入れたので、いったんは分離しています。
```
#!/bin/sh

OCTETS=`hostname -i | tr -s '.' ' '`

i=3
set $OCTETS
if [ $i -ge 10 ]
then
 i=`expr $i - 9`
 shift 9
fi
v1="v1=\$$i"
eval $v1

i=4
if [ $i -ge 10 ]
then
 i=`expr $i - 9`
 shift 9
fi
v2="v2=\$$i"
eval $v2

MYSQL_SERVER_ID=`expr $v1 \* 256 + $v2`

sed -i -e "/# START/,/# END/ s/SERVER_ID/$MYSQL_SERVER_ID/g" /etc/my.cnf
sed -i -e '/# START/,/# END/ s/# server_id/server_id/g' /etc/my.cnf
sed -i -e '/# START/,/# END/ s/# log_bin/log_bin/g' /etc/my.cnf
```

## イメージ作成・docker-compose実行
docker-composeコマンドで実行します。
```
[root@t_kyn029 mysqldocker]# docker-compose up -d
Creating network "mysqldocker_demo-network" with driver "bridge"
Creating volume "mysqldocker_master_db" with default driver
Creating volume "mysqldocker_master_log" with default driver
Creating volume "mysqldocker_slave_db" with default driver
Creating volume "mysqldocker_slave_log" with default driver
Building master
Step 1/6 : FROM alpine:3.17
 ---> 9ed4aefc74f6
Step 2/6 : RUN apk update &&     apk add --no-cache mysql mysql-client netcat-openbsd bash
 ---> Using cache
 ---> adbc751cf7a4
Step 3/6 : EXPOSE 3306
 ---> Using cache
 ---> 25512abf06cd
Step 4/6 : COPY ./entrypoint.sh /entrypoint.sh
 ---> 2373650f235f
Step 5/6 : ENTRYPOINT sh entrypoint.sh
 ---> Running in b0e175661d7f
Removing intermediate container b0e175661d7f
 ---> a268564e1443
Step 6/6 : VOLUME /var/lib/mysql:/var/lib/mysql
 ---> Running in 0fcb19283f5e
Removing intermediate container 0fcb19283f5e
 ---> f1b5afdc83f8

Successfully built f1b5afdc83f8
Successfully tagged mysqldocker_master:latest
WARNING: Image for service master was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Building slave
Step 1/6 : FROM alpine:3.17
 ---> 9ed4aefc74f6
Step 2/6 : RUN apk update &&     apk add --no-cache mysql mysql-client netcat-openbsd bash
 ---> Using cache
 ---> adbc751cf7a4
Step 3/6 : EXPOSE 3306
 ---> Using cache
 ---> 25512abf06cd
Step 4/6 : COPY ./entrypoint.sh /entrypoint.sh
 ---> Using cache
 ---> 2373650f235f
Step 5/6 : ENTRYPOINT sh entrypoint.sh
 ---> Using cache
 ---> a268564e1443
Step 6/6 : VOLUME /var/lib/mysql:/var/lib/mysql
 ---> Using cache
 ---> f1b5afdc83f8

Successfully built f1b5afdc83f8
Successfully tagged mysqldocker_slave:latest
WARNING: Image for service slave was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating t_kyn_001_mysql_slave ... 
Creating t_kyn_001_mysql_master ... 
Creating t_kyn_001_mysql_slave  ... done
Creating t_kyn_001_mysql_master ... done
[root@t_kyn029 mysqldocker]# 
```

## レプリケーション可能かの確認
初期状態ではデータベースは何も入っておらず、レプリケーションはされない状況となります。
レプリケーションをするための初期設定を行います。
ここで

* MasterのDocker内部に入り、データベースに接続し、
レプリケーション用のユーザ及びパスワードを設定します。
★！レプリケーション用パスワード！★は変更してください。
```
[root@t_kyn029 mysqldocker]# docker exec -it t_kyn_001_mysql_master mysql -u root -p mysql
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 10.6.12-MariaDB-log MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

(master) [mysql] > SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.001 sec)

(master) [mysql] > CREATE USER 'repl'@'%' IDENTIFIED BY '★！レプリケーション用パスワード！★';
Query OK, 0 rows affected (0.001 sec)

(master) [mysql] > GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY '★！レプリケーション用パスワード！★';
Query OK, 0 rows affected (0.001 sec)

(master) [mysql] > SHOW MASTER STATUS;
+--------------------+----------+--------------+------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000003 |      706 |              |                  |
+--------------------+----------+--------------+------------------+
1 row in set (0.000 sec)

(master) [mysql] > exit
Bye
[root@t_kyn029 mysqldocker]# 
```

* レプリケーション先のSlaveのDocker内部に入り、データベースに接続します。
STOP SLAVEを実行し、レプリケーションを停止したうえで、以下を設定します。
    * Masterのホスト名：MASTER_HOST
    * Masterのポート番号：MASTER_PORT
    * Masterのユーザ：MASTER_USER（レプリケーション用のユーザ）
    * Masterのパスワード：MASTER_PASSWORD（レプリケーション用のパスワード）
    * Masterのログポジション：MASTER_LOG_POS

```
[root@t_kyn029 mysqldocker]# docker exec -it t_kyn_001_mysql_slave mysql -u root -p mysql
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.6.12-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

(slave) [mysql] > STOP SLAVE;
Query OK, 0 rows affected, 1 warning (0.000 sec)

(slave) [mysql] > CHANGE MASTER TO MASTER_HOST='t_kyn_001_mysql_master', MASTER_PORT=3306 ,MASTER_USER='repl',MASTER_PASSWORD='★！レプリケーション用パスワード！★'  , MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=706;
Query OK, 0 rows affected (0.062 sec)

(slave) [mysql] > START SLAVE;
Query OK, 0 rows affected (0.002 sec)

(slave) [mysql] > show slave status\G;
*************************** 1. row ***************************
                Slave_IO_State: Waiting for master to send event
                   Master_Host: t_kyn_001_mysql_master
                   Master_User: repl
                   Master_Port: 3306
                 Connect_Retry: 60
               Master_Log_File: mariadb-bin.000003
           Read_Master_Log_Pos: 706
                Relay_Log_File: mysqld-relay-bin.000002
                 Relay_Log_Pos: 557
         Relay_Master_Log_File: mariadb-bin.000003
              Slave_IO_Running: Yes
             Slave_SQL_Running: Yes
               Replicate_Do_DB: 
           Replicate_Ignore_DB: 
            Replicate_Do_Table: 
        Replicate_Ignore_Table: 
       Replicate_Wild_Do_Table: 
   Replicate_Wild_Ignore_Table: 
                    Last_Errno: 0
                    Last_Error: 
                  Skip_Counter: 0
           Exec_Master_Log_Pos: 706
               Relay_Log_Space: 867
               Until_Condition: None
                Until_Log_File: 
                 Until_Log_Pos: 0
            Master_SSL_Allowed: No
            Master_SSL_CA_File: 
            Master_SSL_CA_Path: 
               Master_SSL_Cert: 
             Master_SSL_Cipher: 
                Master_SSL_Key: 
         Seconds_Behind_Master: 0
 Master_SSL_Verify_Server_Cert: No
                 Last_IO_Errno: 0
                 Last_IO_Error: 
                Last_SQL_Errno: 0
                Last_SQL_Error: 
   Replicate_Ignore_Server_Ids: 
              Master_Server_Id: 1
                Master_SSL_Crl: 
            Master_SSL_Crlpath: 
                    Using_Gtid: No
                   Gtid_IO_Pos: 
       Replicate_Do_Domain_Ids: 
   Replicate_Ignore_Domain_Ids: 
                 Parallel_Mode: optimistic
                     SQL_Delay: 0
           SQL_Remaining_Delay: NULL
       Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
              Slave_DDL_Groups: 0
Slave_Non_Transactional_Groups: 0
    Slave_Transactional_Groups: 0
1 row in set (0.001 sec)

ERROR: No query specified

(slave) [mysql] > exit
Bye
[root@t_kyn029 mysqldocker]# 
```

## データがレプリケーションされるか確認
データがSlave側にレプリケーションされるか確認します。

Master側のDocker内部に入り、データベースに接続します。
適当にデータベース作成、テーブルを作成します。
```
[root@t_kyn029 mysqldocker]# docker exec -it t_kyn_001_mysql_master mysql -u root -p mysql
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 6
Server version: 10.6.12-MariaDB-log MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

(master) [mysql] > create database unkomandbrepltest;
Query OK, 1 row affected (0.001 sec)

(master) [mysql] > use unkomandbrepltest
Database changed
(master) [unkomandbrepltest] > create table unkomantable (id int);insert into unkomantable values (1) ;insert into unkomantable values (2);sel ect * from unkomantable;
Query OK, 0 rows affected (0.008 sec)

Query OK, 1 row affected (0.003 sec)

Query OK, 1 row affected (0.002 sec)

+------+
| id   |
+------+
|    1 |
|    2 |
+------+
2 rows in set (0.001 sec)

(master) [unkomandbrepltest] > exit
Bye
[root@t_kyn029 mysqldocker]# 
```

* レプリケーション先（SlaveのDockerの内部）に入り、データベースに接続します。
Master側で作成したデータベース、テーブルが作成されていることが確認できます。

```
[root@t_kyn029 mysqldocker]# docker exec -it t_kyn_001_mysql_slave mysql -u root -p mysql
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 6
Server version: 10.6.12-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

(slave) [mysql] > show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
| unkomandbrepltest  |
+--------------------+
6 rows in set (0.001 sec)

(slave) [mysql] > use unkomandbrepltest;
Database changed
(slave) [unkomandbrepltest] > select * from unkomantable;
+------+
| id   |
+------+
|    1 |
|    2 |
+------+
2 rows in set (0.001 sec)

(slave) [unkomandbrepltest] > exit
Bye
[root@t_kyn029 mysqldocker]# 
```

## 事後作業
後続のKubernetesでの構築を行うため、
docker-composeしたコンテナ及び関連するボリュームやネットワークは不要となるため、削除します。

* docker-composeしたコンテナを削除

```
[root@t_kyn029 mysqldocker]# docker-compose down --rmi all --volumes --remove-orphans
Stopping t_kyn_001_mysql_master ... 
Stopping t_kyn_001_mysql_slave  ... 
Stopping t_kyn_001_mysql_slave  ... doneStopping t_kyn_001_mysql_master ... doneRemoving t_kyn_001_mysql_master ... 
Removing t_kyn_001_mysql_slave  ... 
Removing t_kyn_001_mysql_master ... doneRemoving t_kyn_001_mysql_slave  ... doneRemoving network mysqldocker_demo-network
Removing volume mysqldocker_master_db
Removing volume mysqldocker_master_log
Removing volume mysqldocker_slave_db
Removing volume mysqldocker_slave_log
Removing image mysqldocker_master
Removing image mysqldocker_slave
[root@t_kyn029 mysqldocker]# 
```

また、docker自体のログやデータベースファイルは残ってしまうので、通り削除します。
```
[root@t_kyn029 mysqldocker]# rm -rfv ./master_log ./master_db ./slave_log/ ./slave_db
[root@t_kyn029 mysqldocker]# mkdir -pvm 777 ./master_log ./slave_log/
```

以上になります。