用Docker搭建MySQL主从多节点集群

MySQL 主从同步分为 5 个步骤:

master 节点将数据的更新记录写到 binary log 中。

slave 节点开启 IO 线程连接 master 节点,请求获取指定 binary log 文件的指定位置之后的日志。

master 节点的 binary log dump 线程将指定的 binary log 信息推送给 slave 节点。

slave 节点的 IO 线程接收到消息后,将日志内容写入 relay log 文件。

slave 节点的 SQL 线程检测到 relay log 新增了内容,马上解析 relay log 文件生成相应的 SQL 语句,并将这些 SQL 语句重放到数据库,保证主从数据一致性。

通过Dockerfile构建一主一从

创建目录结构

1
2
3
4
5
- docker-compose.yaml
- mysql/master/Dockerfil
- mysql/master/cluster.cnf
- mysql/slave/Dockerfil
- mysql/slave/cluster.cnf

docker-compose.yaml内容

 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
version: "3"
services:
  mysql-master:
    build:
      context: ./
      dockerfile: mysql/master/Dockerfile
    container_name: mysql-master
    volumes:
      - ./mysql/master/data:/var/lib/mysql
    restart: always
    ports:
      - 3305:3306
    links:
      - mysql-slave

  mysql-slave:
    build:
      context: ./
      dockerfile: mysql/slave/Dockerfile
    container_name: mysql-slave
    volumes:
      - ./mysql/slave/data:/var/lib/mysql
    restart: always
    ports:
      - 3306:3306

master 节点的 cluster.cnf 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[mysqld]
server_id=100
binlog-ignore-db=mysql
log-bin=replicas-mysql-bin
binlog_cache_size=1M
binlog_format=mixed
slave_skip_errors=1062

# MySQL 8.x,需要如下配置
default_authentication_plugin=mysql_native_password
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

master 节点的 Dockerfile 内容

1
2
3
FROM mysql:latest
ADD ./mysql/master/cluster.cnf /etc/mysql/conf.d/cluster.cnf
ENV MYSQL_ROOT_PASSWORD=password

slave 节点的 cluster.cnf 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[mysqld]
server_id=101
binlog-ignore-db=mysql
binlog_cache_size=1M
binlog_format=mixed
slave_skip_errors=1062
relay_log=replicas-mysql-relay-bin
log_slave_updates=1
read_only=1

# MySQL 8.x,需要如下配置
default_authentication_plugin=mysql_native_password
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

slave 节点的 Dockerfile 内容

1
2
3
FROM mysql:latest
ADD ./mysql/slave/cluster.cnf /etc/mysql/conf.d/cluster.cnf
ENV MYSQL_ROOT_PASSWORD=password

启动容器

1
2
> docker-compose up -d mysql-master mysql-slave
> docker ps

建立主从关系

连接主节点查看复制位点File,Postion

1
2
3
> docker exec -it mysql-master bash
> mysql -uroot -p
> show master status;

连接从节点设置复制节点和位点参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> docker exec -it mysql-slave bash
> mysql -uroot -p
> reset master;
> CHANGE MASTER TO
    MASTER_HOST='mysql-master',
    MASTER_USER='root',
    MASTER_PASSWORD=<root password>,
    MASTER_LOG_FILE=<master File>,
    MASTER_LOG_POS=<master Position>;
> start slave;
> show slave status\G

连接主节点执行sql操作测试主从复制健康状态

1
2
3
> docker exec -it mysql-master bash
> mysql -uroot -p
> create database cluster_test;
1
2
3
> docker exec -it mysql-slave bash
> mysql -uroot -p
> show databases;

一主多从

docker-compose.yaml

 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
68
version: '3'
services:
    mysql-master:
        container_name: mysql-master
        hostname: mysql-master
        image: "mysql:5.7"
        ports:
            - "33060:3306"
        networks: ## 引入外部预先定义的网段
            srm-mysql:
                ipv4_address: 173.200.6.110   #设置ip地址
        volumes:
            - ./mysql/master/etc:/etc/mysql
            - ./mysql/master/var/lib:/var/lib/mysql
            - ./mysql/master/my.cnf:/etc/my.cnf
            - ./master/init_db/:/docker-entrypoint-initdb.d/
        environment:
            - TZ=Asia/Shanghai
            - MYSQL_ROOT_PASSWORD=123456
        command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        restart: always

    mysql-slave-1:
        container_name: mysql-slave-1
        hostname: mysql-slave-1
        image: "mysql:5.7"
        ports:
            - "33070:3306"
        networks: ## 引入外部预先定义的网段
            srm-mysql:
                ipv4_address: 173.200.6.120   #设置ip地址
        volumes:
            - ./mysql/slave1/etc:/etc/mysql
            - ./mysql/slave1/var/lib:/var/lib/mysql
            - ./mysql/slave1/my.cnf:/etc/my.cnf
            - ./slave-1/init_db/:/docker-entrypoint-initdb.d/
        environment:
            - TZ=Asia/Shanghai
            - MYSQL_ROOT_PASSWORD=123456
        command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        restart: always
    mysql-slave-2:
        container_name: mysql-slave-2
        hostname: mysql-slave-2
        image: "mysql:5.7"
        ports:
            - "33080:3306"
        networks: ## 引入外部预先定义的网段
            srm-mysql:
                ipv4_address: 173.200.6.130   #设置ip地址
        volumes:
            - ./mysql/slave2/etc:/etc/mysql
            - ./mysql/slave2/var/lib:/var/lib/mysql
            - ./mysql/slave2/my.cnf:/etc/my.cnf
            - ./slave-2/init_db/:/docker-entrypoint-initdb.d/
        environment:
            - TZ=Asia/Shanghai
            - MYSQL_ROOT_PASSWORD=123456
        command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        restart: always
# 设置网络模块
networks:
    # 自定义网络
    srm-mysql:
        driver: bridge
        ipam: #定义网段
            config:
                - subnet: "173.200.6.0/24"

主节点的my.cnf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[mysqld]
server_id =  1

# 开启GTID模式
gtid-mode  =  ON
enforce-gtid-consistency    =   1

# 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
binlog-ignore-db    =   mysql
# 开启二进制日志功能,可以随便取,最好有含义(关键就是这里了)
log-bin             =   mysql-bin
# 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存
binlog_cache_size   =   1M
# 主从复制的格式(mixed,statement,row,默认格式是statement)
binlog_format       =   mixed
# 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days    =   7
# 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
# 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors   =   1062
# log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates   =   ON

从节点配置my.cnf,修改server_id

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[mysqld]
server_id   = 2

gtid-mode                =  ON
enforce-gtid-consistency =  1

binlog-ignore-db    =   mysql
log-bin             =   mysql-slave1-bin
binlog_cache_size   =   1M
binlog_format       =   mixed
expire_logs_days    =   7
slave_skip_errors   =   1062
relay_log           =   mysql-relay-bin
log_slave_updates   =   ON
read_only           =   1

连接主节点创建复制账号

1
2
3
4
5
> docker exec -it mysql-master bash
> mysql -uroot -p

> create user 'repl'@'%' identified by 'repl';
> grant replication client,replication slave on *.* to 'repl'@'%';

连接从节点重置主

1
2
3
4
5
6
> docker exec -it mysql-slave-1 bash
> mysql -uroot -p

> reset master;
> CHANGE MASTER TO MASTER_HOST='mysql-master',MASTER_USER='repl',MASTER_PASSWORD='repl',MASTER_PORT=3306,MASTER_AUTO_POSITION=1;
> start slave;

mha高可用

docker-compose.yaml

 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
version: "2"

services:
    mha_share:
        image: debian:jessie
        volumes:
            - "./employees_share/:/mha_share/"
    mha_node:
        build: ./mha_node
        image: prontera/mha_node
        read_only: true
    mha_manager:
        build: ./mha_manager
        image: prontera/mha_manager
        read_only: true
    master:
        image: prontera/mha_node
        depends_on:
            - mha_node
        ports:
            - "3406:3306"
        volumes:
            - "./employees_db/:/docker-entrypoint-initdb.d/:ro"
            - "./employees_master/lib/:/var/lib/mysql/"
            - "./employees_master/log/:/var/log/mysql/"
            - "./employees_master/conf.d/:/etc/mysql/mysql.conf.d/"
        volumes_from:
            - mha_share
        env_file:
            - ./account.env
        environment:
            - MYSQL_USER=prontera
            - MYSQL_PASSWORD=123123
    slave_1:
        image: prontera/mha_node
        depends_on:
            - master
        ports:
            - "3407:3306"
        volumes:
            - "./employees_slave_1/lib/:/var/lib/mysql/"
            - "./employees_slave_1/log/:/var/log/mysql/"
            - "./employees_slave_1/conf.d/:/etc/mysql/mysql.conf.d/"
        volumes_from:
            - mha_share
        env_file:
            - ./account.env
    manager:
        image: prontera/mha_manager
        depends_on:
            - mha_manager
            - slave_1
        volumes_from:
            - mha_share
        entrypoint:
            tailf /dev/null
        env_file:
            - ./account.env

参考