使用docker搭建MySQL8主从架构

161 阅读4分钟

平时做实验需要用到数据库, 自己的 NAS 又有点剩余性能, 所以考虑在 NAS 上搭建一个常用的数据库.

NAS 系统使用群晖的 DSM7.0.1, 本质上是基于某个 Linux 内核的改版系统, 所以选择耦合度低的 docker 方式来部署, 部署过程与普通的 Linux 环境上一样. 考虑到 NAS 的可视化 docker 界面做文件映射时选择不到一些系统的目录, 所以还是建议直接 ssh 到 NAS 上使用 root 用户操作.

其实用 docker 部署数据库与其设计理念有点冲突了, 理想的 docker 应用应该是无状态的, docker 容器不耦合宿主机. 使用 docker 部署持久型数据库不但违背这一理念, 同时也会让数据库损失一部分性能. 不过由于并非生产环境, 实验的物理机虚拟机有限, 而且 docker 应用不但有开箱即用的特性, 而且多实例部署也方便, 即使是部署数据库, 也能一定程度上减少与系统的耦合, 所以就不在意这个问题了.


准备目录与配置文件

想法: 暂时使用一个 MySQL8 做主库, 一个 MySQL8 做从库, 以后若想扩展多个从库或者扩展不同版本的数据库做实验都是可以的.

镜像: mysql/mysql-server:8.0.30

在 NAS 上新建目录用于映射到容器内, 如下:

cluster-master-slave/
├── mysql-8.0.30-master
│   ├── conf
│   └── data
└── mysql-8.0.30-slave1
    ├── conf
    └── data

先随便 docker start 个MySQL 镜像, 然后 docker exec 进去看看配置文件位置:

bash-4.4# mysql --help |grep my.cnf -A 1 -B 1                                                                                                                                                        
  -P, --port=#        Port number to use for connection or 0 for default to, in                                                                                                                      
                      order of preference, my.cnf, $MYSQL_TCP_PORT,                                                                                                                                  
                      /etc/services, built-in default (3306).                                                                                                                                        
--                                                                                                                                                                                                   
Default options are read from the following files in the given order:                                                                                                                                
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf                                                                                                                                              
The following groups are read: mysql client 

这几个位置都找找看, 发现自带的配置文件就是 /etc/my.cnf , 退出 docker bash, 然后直接 docker cp 出来, 比如我的环境下是执行:

docker cp mysql-8.0.30:/etc/my.cnf /volume1/docker/mysql/cluster-master-slave/mysql-8.0.30-master/conf/my.cnf
docker cp mysql-8.0.30:/etc/my.cnf /volume1/docker/mysql/cluster-master-slave/mysql-8.0.30-slave1/conf/my.cnf

然后稍微做下集群化的修改, 在 master 的配置文件的 [mysqld] 模块上加如下配置:

server_id=1
log-bin=mysql-bin
read-only=0
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
binlog_format=STATEMENT
#binlog_format=ROW
#binlog_format=MIXED

在 slave1 的配置文件的 [mysqld] 模块上加如下配置:

server_id=2
log-bin=mysql-bin
read-only=1
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema

配置主要是忽略部分系统表的同步, 以及从库开启只读模式.

注: 从库的只读模式只对非 SUPER 用户起作用, 同时不影响主从复制的写功能.

最终准备好的目录是:

cluster-master-slave/
├── mysql-8.0.30-master
│   ├── conf
│   │   └── my.cnf
│   └── data
└── mysql-8.0.30-slave1
    ├── conf
    │   └── my.cnf
    └── data

当然自己写或者拷贝官网的文件也行, 但因为mysql 版本众多, 而且docker有现成镜像的配置文件可以用, 所以我就选择用镜像自生成的, 肯定是最不容易出错的.

启动容器

起名是非常重要的, 直接决定了以后的管理成本

确定容器名称(因为我的 cluster1 为 nacos 集群, 所以 MySQL 集群就顺延使用 cluster2 了)

  • 主服务器 cluster2-master-mysql-8.0.30
  • 从服务器 cluster2-slave1-mysql-8.0.30

创建 master :

docker run --name cluster2-master-mysql-8.0.30 -d -p 4306:3306 -e MYSQL_ROOT_PASSWORD=root -v /volume1/docker/mysql/cluster-master-slave/mysql-8.0.30-master/data:/var/lib/mysql -v /volume1/docker/mysql/cluster-master-slave/mysql-8.0.30-master/conf/my.cnf:/etc/my.cnf mysql/mysql-server:8.0.30

创建 slave1 :

docker run --name cluster2-slave1-mysql-8.0.30 -d -p 4307:3306 -e MYSQL_ROOT_PASSWORD=root -v /volume1/docker/mysql/cluster-master-slave/mysql-8.0.30-slave1/data:/var/lib/mysql -v /volume1/docker/mysql/cluster-master-slave/mysql-8.0.30-slave1/conf/my.cnf:/etc/my.cnf mysql/mysql-server:8.0.30

创建完成后进入主库创建同步账户并赋予权限:

create user 'slave1'@'%' identified with mysql_native_password by '123456';
grant replication slave on *.* to 'slave1'@'%';
flush privileges;

查看主库状态:

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |     1582 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.02 sec)

在从库上执行同步语句:

change master to master_host='nas.me', master_user='slave1', master_password='123456', master_port=4306, master_log_file='mysql-bin.000003', master_log_pos=1582;

开始同步, 并查看同步状态:

start slave;
show slave status\G

如果发现 status 中有任何错误, 则停止从库同步:

stop slave;

排查完原因后, 可能需要重置同步:

reset slave;

重新 start slave 后当看到如下显示说明成功了:

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for source to send event
                  Master_Host: nas.me
                  Master_User: slave1
                  Master_Port: 4306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 4487
               Relay_Log_File: 80191758b1f2-relay-bin.000002
                Relay_Log_Pos: 1002
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB: mysql,sys,information_schema,performance_schema
           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: 4487
              Relay_Log_Space: 1219
              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_UUID: b769452d-1cac-11ed-a13f-0242ac110008
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
       Master_public_key_path:
        Get_master_public_key: 0
            Network_Namespace:
1 row in set, 1 warning (0.01 sec)

中途遇到问题多 goo 几下, 注意 MySQL8 与 MySQL5 的差异, 基本不会有太大问题.