Docker 部署 MySQL 8 集群(一主二从)

  • 主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中
  • 对于多级复制,数据库服务器即可充当主机,也可充当从机
  • MySQL 主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新

1. 集群部署

  • 环境准备
1
2
3
# Docker:略
$ cd /opt/app/docker/mysql8
$ mkdir -p {master,slave1,slave2}/{conf,data,logs}
  • 主节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ cd master
$ vi conf/my.cnf
[mysqld]
## 设置server_id,注意要唯一
server-id=1
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启binlog
log-bin=app-mysql-bin
## 设置binlog使用内存大小(事务)
binlog_cache_size=1M
## binlog格式(mixed、statement、row,默认statement)
binlog_format=mixed
## binlog过期清理时间。默认0,表示不自动清理
binlog_expire_logs_seconds=604800
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
replica_skip_errors=1062
## 字符编码
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
secure-file-priv=/var/lib/mysql
skip-name-resolve
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4

$ vi start.sh
docker run -d -p 3307:3306 --name mysql-master \
-v $PWD/logs:/var/log/mysql \
-v $PWD/data:/var/lib/mysql \
-v $PWD/conf:/etc/mysql \
# https://stackoverflow.com/questions/55559386/how-to-fix-mbind-operation-not-permitted-in-mysql-error-log
--cap-add=sys_nice \
-e MYSQL_ROOT_PASSWORD=root \
mysql:8
$ chmod +x start.sh
$ ./start.sh
  • 从节点1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ cd slave1
$ vi conf/my.cnf
[mysqld]
## 设置server_id,注意要唯一
server-id=2
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启binlog功能,以备Slave作为其它数据库实例的Master时使用
log-bin=app-mysql-slave-bin
## 设置binlog使用内存大小(事务)
binlog_cache_size=1M
## binlog格式(mixed、statement、row,默认statement)
binlog_format=mixed
## binlog过期清理时间。默认0,表示不自动清理
binlog_expire_logs_seconds=604800
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
replica_skip_errors=1062
## 配置中继日志
relay_log=app-mysql-relay-bin
## 表示slave将复制事件写进自己的二进制日志
log_replica_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
## 如果需要同步函数或者存储过程
log_bin_trust_function_creators=true
## 字符编码
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
secure-file-priv=/var/lib/mysql
skip-name-resolve
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4

$ vi start.sh
docker run -d -p 3308:3306 --name mysql-slave1 \
-v $PWD/logs:/var/log/mysql \
-v $PWD/data:/var/lib/mysql \
-v $PWD/conf:/etc/mysql \
--cap-add=sys_nice \
-e MYSQL_ROOT_PASSWORD=root \
mysql:8
$ chmod +x start.sh
$ ./start.sh
  • 从节点2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ cd slave2
$ vi conf/my.cnf
[mysqld]
## 设置server_id,注意要唯一
server-id=3
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启binlog功能,以备Slave作为其它数据库实例的Master时使用
log-bin=app-mysql-slave-bin
## 设置binlog使用内存大小(事务)
binlog_cache_size=1M
## binlog格式(mixed、statement、row,默认statement)
binlog_format=mixed
## binlog过期清理时间。默认0,表示不自动清理
binlog_expire_logs_seconds=604800
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
replica_skip_errors=1062
## 配置中继日志
relay_log=app-mysql-relay-bin
## 表示slave将复制事件写进自己的二进制日志
log_replica_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
## 如果需要同步函数或者存储过程
log_bin_trust_function_creators=true
## 字符编码
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
secure-file-priv=/var/lib/mysql
skip-name-resolve
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4

$ vi start.sh
docker run -d -p 3309:3306 --name mysql-slave2 \
-v $PWD/logs:/var/log/mysql \
-v $PWD/data:/var/lib/mysql \
-v $PWD/conf:/etc/mysql \
--cap-add=sys_nice \
-e MYSQL_ROOT_PASSWORD=root \
mysql:8
$ chmod +x start.sh
$ ./start.sh

2. 集群配置

  • 主节点配置
1
2
3
4
5
6
7
8
9
10
11
$ docker exec -it mysql-master /bin/bash
root@9fcd4440d1bb:/# mysql -u root -p
mysql> CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
mysql> FLUSH PRIVILEGES;
mysql> show master status;
+----------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------------+----------+--------------+------------------+-------------------+
| app-mysql-bin.000003 | 880 | | mysql | |
+----------------------+----------+--------------+------------------+-------------------+
  • 从节点1/2配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ docker exec -it mysql-slave1 /bin/bash
root@338d4b2a47af:/# mysql -uroot -p
# 配置连接的参数
mysql> change master to master_host='10.4.7.101', master_port=3307, master_user='slave', master_password='123456', master_log_file='app-mysql-bin.000003', master_log_pos=880, master_connect_retry=30, get_master_public_key=1;
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 10.4.7.101
Master_User: slave
Master_Port: 3307
Connect_Retry: 30
Master_Log_File: app-mysql-bin.000003
Read_Master_Log_Pos: 880
Relay_Log_File: app-mysql-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: app-mysql-bin.000003
Slave_IO_Running: No
Slave_SQL_Running: No
......
# 启动同步
mysql> start slave;
# 查看是否成功(失败需要先停止连接后检查账号密码、地址、pos等参数)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 10.4.7.101
Master_User: slave
Master_Port: 3307
Connect_Retry: 30
Master_Log_File: app-mysql-bin.000003
Read_Master_Log_Pos: 880
Relay_Log_File: app-mysql-relay-bin.000002
Relay_Log_Pos: 328
Relay_Master_Log_File: app-mysql-bin.000003
Slave_IO_Running: Yes # 已开始
Slave_SQL_Running: Yes # 已开始
......
# 停止连接,如果成功了无需使用该命令
mysql> # stop slave;
mysql> # reset slave;

3. 集群测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 主节点查询
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 3 | | 3306 | 1 | f5a894d5-7c88-11ee-9031-0242ac110004 |
| 2 | | 3306 | 1 | bb438a7c-7c88-11ee-b920-0242ac110003 |
+-----------+------+------+-----------+--------------------------------------+

# 主节点新增数据
mysql> create database test;
mysql> use test;
mysql> create table t1(id int, name varchar(20));
mysql> insert into t1(id, name) values (1,'hello');
mysql> select * from t1;

# 从节点查询数据
mysql> use test;
mysql> select * from t1;

4. 部署问题

(1) Authentication plugin ‘caching_sha2_password’ reported error: Authentication require secure connection

  • 在 MySQL 8 之前,身份验证的插件是 mysql_native_password,在 MySQL 8 中,caching_sha2_password 是默认的身份验证插件,安全性更高
  • 如果复制用户的身份验证插件是 caching_sha2_password,则需要指定 GET_MASTER_PUBLIC_KEY=1;如果是 mysql_native_password 则不需要指定
1
2
3
4
5
mysql> CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
mysql> ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

$ vi my.cnf
default_authentication_plugin=mysql_native_password

(2) mbind: Operation not permitted

5. 5.7 集群部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
$ mkdir -p {3307..3309}/{logs,data,conf}

$ cd 3307
$ vi start.sh
docker run -p 3307:3306 --name mysql-master \
-v $PWD/logs:/var/log/mysql \
-v $PWD/data:/var/lib/mysql \
-v $PWD/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
$ vi conf/my.cnf
[mysqld]
server_id=101
binlog-ignore-db=mysql
log-bin=mall-mysql-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062

$ chmod +x start.sh
$ ./start.sh

$ docker exec -it mysql-master /bin/bash
root@1cf918631596:/# mysql -u root -p
mysql> CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
mysql> FLUSH PRIVILEGES;

$ cd 3308
$ vi start.sh
docker run -p 3308:3306 --name mysql-slave \
-v $PWD/logs:/var/log/mysql \
-v $PWD/data:/var/lib/mysql \
-v $PWD/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
$ vi conf/my.cnf
[mysqld]
server_id=102
binlog-ignore-db=mysql
log-bin=mall-mysql-slave1-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
relay_log=mall-mysql-relay-bin
log_slave_updates=1
read_only=1

$ chmod +x start.sh
$ ./start.sh

$ docker exec -it mysql-master /bin/bash
root@1cf918631596:/# mysql -uroot -p
mysql> show master status;
+-----------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------------+----------+--------------+------------------+-------------------+
| mall-mysql-bin.000003 | 617 | | mysql | |
+-----------------------+----------+--------------+------------------+-------------------+

$ docker exec -it mysql-slave /bin/bash
root@8c339c111456:/# mysql -uroot -p
mysql> change master to master_host='10.4.7.101', master_port=3307, master_user='slave', master_password='123456', master_log_file='mall-mysql-bin.000003', master_log_pos=617, master_connect_retry=30;
mysql> start slave;
mysql> show slave status \G;

参考