docker篇-(docker-compose搭建mysql高可用主从集群)

docker-compose安装mysql主从集群

  • 为什么要使用mysql主从集群
  • 基于docker,手动搭建mysql主从集群
    • 拉取mysql镜像
    • 启动镜像
    • 重新启动镜像,并设置master需要配置的参数
    • 进入容器,创建主从同步账号
    • 启动slave容器,实现主从同步
    • 测试同步
  • 基于docker,使用脚本的方式实现主从
    • 编写master用于创建同步账号的脚本
    • 启动mysql-master,挂载脚本
    • 编写mysql-slave脚本
    • 启动mysql-slave
    • 测试同步数据
  • 使用docker-compose,实现一键部署一主二从
    • 编写docker-compose.yml文件
    • 运行docker-compose.yaml
    • 查看三台容器的日志
      • mysql-master
      • mysql-slave1
      • mysql-slave2
    • 测试数据同步
      • mysql-master
      • mysql-slave1
      • mysql-slave2
  • 加入nginx,实现slave的负载均衡
    • 创建nginx负责均衡的配置文件
      • 创建nginx.conf,开启stream支持
      • 编写mysql.conf
    • 修改docker-compose.yml
    • 执行docker-compose
    • 使用navicat连接从库
    • 在mysql-master中创建测试数据,并进入navicat查看情况
  • 写在最后

为什么要使用mysql主从集群

简单来说,如果对数据库的读和写都在同一个数据库服务器中操作,数据库的压力会变大,导致读写性能会下降。为了提升数据库性能,优化用户体验,可以通过做主从复制(读写分离)来减轻主数据库的负载。 而且如果主数据库宕机,可快速将业务系统切换到从数据库上,可避免数据丢失。
在这里,我为什么使用docker来模拟mysql主从集群,是因为为了切合我博客的标题,使用docker容器化的方式实现mysql主从集群一键部署

基于docker,手动搭建mysql主从集群

拉取mysql镜像

这里使用的是mysql8.0.13版本的镜像,为了防止后续镜像发生变化,所以使用一个相对稳定版本来部署

docker pull mysql:8.0.13

启动镜像

启动镜像,测试镜像是否能正常运行

docker run --name mysql -e MYSQL_ROOT_PASSWORD="123456" -d mysql:8.0.13

docker篇-(docker-compose搭建mysql高可用主从集群)_第1张图片

重新启动镜像,并设置master需要配置的参数

#关掉之前的镜像
docker rm -f mysql
#启动新的镜像,设置server-id和开启logbin
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD="123456" -d mysql:8.0.13 --server-id=1 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --log-bin=mysql-bin --sync_binlog=1

进入容器,创建主从同步账号

#查看容器当前ip网段,后续创建同步账号会需要
docker inspect mysql
docker exec -ti mysql bash
mysql -uroot -p123456
CREATE USER 'sync_root'@'172.17.%.%' IDENTIFIED BY 'sync_123456';
GRANT REPLICATION SLAVE ON *.* TO 'sync_root'@'172.17.%.%';
FLUSH PRIVILEGES;
#查看master的binlog信息
SHOW MASTER STATUS;

docker篇-(docker-compose搭建mysql高可用主从集群)_第2张图片
docker篇-(docker-compose搭建mysql高可用主从集群)_第3张图片

启动slave容器,实现主从同步

#启动容器,等待mysql正常启动
docker run --name slave -e MYSQL_ROOT_PASSWORD="123456" -d mysql:8.0.13 --server-id=2 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
#进入容器,连接master,然后开启同步
docker exec -ti slave bash
mysql -uroot -p123456
# 这里master_host就是刚刚看到的master的ip,master_user就是我们创建用于同步的账号,master_log_file和master_log_pos就是通过show master status获得到的
CHANGE MASTER TO MASTER_HOST='172.17.0.2',MASTER_USER='sync_root',MASTER_PASSWORD='sync_123456',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=900;
#开启同步
START SLAVE;
#查看slave同步状态
SHOW SLAVE STATUS\G

如果出现以下情况
是mysql从节点正处于连接状态,等待一会儿即可,直到后续日志打印出同步信息即可,如果是Yes则不需要等待
docker篇-(docker-compose搭建mysql高可用主从集群)_第4张图片
同步信息如下
在这里插入图片描述

启动成功之后如下
docker篇-(docker-compose搭建mysql高可用主从集群)_第5张图片

测试同步

1.进入master,创建一个测试数据库

docker exec -ti mysql bash
mysql -uroot -p123456
CREATE DATABASE test;

docker篇-(docker-compose搭建mysql高可用主从集群)_第6张图片

2.进入slave,查看对应的test库是否同步过来

docker exec -ti slave bash
mysql -uroot -p123456
SHOW DATABASES;

docker篇-(docker-compose搭建mysql高可用主从集群)_第7张图片

基于docker,使用脚本的方式实现主从

为什么说是使用脚本的方式呢,因为在docker容器里面的mysql,是通过entrypoint.sh来启动mysql的,如果mysql是第一次启动,在初始化完成之后,会去加载/docker-entrypoint-initdb.d这个目录下面的脚本执行,所以我们可以编写同步脚本,将其挂载在这个目录下即可
以下操作都在mysql目录中执行,我的目录如下图
在这里插入图片描述

编写master用于创建同步账号的脚本

注意:在执行到这一步之前,请关掉上面启动的mysql和slave两个容器,可以执行以下命令

docker rm -f mysql
docker rm -f slave
#创建对应目录
mkdir -p ./init/{master,slave}
#将master初始化脚本写入到init/master目录下
cat > ./init/master/create_sync_user.sh <<EOF
#!/bin/bash
#定义用于同步的用户名
MASTER_SYNC_USER=\${MASTER_SYNC_USER:-sync_admin}
#定义用于同步的用户密码
MASTER_SYNC_PASSWORD=\${MASTER_SYNC_PASSWORD:-123456}
#定义用于登录mysql的用户名
ADMIN_USER=\${ADMIN_USER:-root}
#定义用于登录mysql的用户密码
ADMIN_PASSWORD=\${ADMIN_PASSWORD:-123456}
#定义运行登录的host地址
ALLOW_HOST=\${ALLOW_HOST:-%}
#定义创建账号的sql语句
CREATE_USER_SQL="CREATE USER '\$MASTER_SYNC_USER'@'\$ALLOW_HOST' IDENTIFIED BY '\$MASTER_SYNC_PASSWORD';"
#定义赋予同步账号权限的sql,这里设置两个权限,REPLICATION SLAVE,属于从节点副本的权限,REPLICATION CLIENT是副本客户端的权限,可以执行show master status语句
GRANT_PRIVILEGES_SQL="GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO '\$MASTER_SYNC_USER'@'\$ALLOW_HOST';"
#定义刷新权限的sql
FLUSH_PRIVILEGES_SQL="FLUSH PRIVILEGES;"
#执行sql
mysql -u"\$ADMIN_USER" -p"\$ADMIN_PASSWORD" -e "\$CREATE_USER_SQL \$GRANT_PRIVILEGES_SQL \$FLUSH_PRIVILEGES_SQL"
EOF

启动mysql-master,挂载脚本

创建网卡,保证master和slave都在同一个网段

docker network create --driver=bridge --subnet=10.10.0.0/16 mysql
docker run --name mysql-master -v ${PWD}/init/master:/docker-entrypoint-initdb.d -e MYSQL_ROOT_PASSWORD="123456" -e MASTER_SYNC_USER="sync_root" -e MASTER_SYNC_PASSWORD="sync_123456" -e ADMIN_USER="root" -e ADMIN_PASSWORD="123456" -e ALLOW_HOST="10.10.%.%" -e TZ="Asia/Shanghai" --ip 10.10.10.10 --network mysql -d mysql:8.0.13 --server-id=1 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --log-bin=mysql-bin --sync_binlog=1

编写mysql-slave脚本

mkdir -p ./init/slave
cat > ./init/slave/slave.sh <<EOF
  #定义连接master进行同步的账号
  SLAVE_SYNC_USER="\${SLAVE_SYNC_USER:-sync_admin}"
  #定义连接master进行同步的账号密码
  SLAVE_SYNC_PASSWORD="\${SLAVE_SYNC_PASSWORD:-123456}"
  #定义slave数据库账号
  ADMIN_USER="\${ADMIN_USER:-root}"
  #定义slave数据库密码
  ADMIN_PASSWORD="\${ADMIN_PASSWORD:-123456}"
  #定义连接master数据库host地址
  MASTER_HOST="\${MASTER_HOST:-%}"
  #等待10s,保证master数据库启动成功,不然会连接失败
  sleep 10
  #连接master数据库,查询二进制数据,并解析出logfile和pos,这里同步用户要开启 REPLICATION CLIENT权限,才能使用SHOW MASTER STATUS;
  RESULT=\`mysql -u"\$SLAVE_SYNC_USER" -h\$MASTER_HOST -p"\$SLAVE_SYNC_PASSWORD" -e "SHOW MASTER STATUS;" | grep -v grep |tail -n +2| awk '{print \$1,\$2}'\`
  #解析出logfile
  LOG_FILE_NAME=\`echo \$RESULT | grep -v grep | awk '{print \$1}'\`
  #解析出pos
  LOG_FILE_POS=\`echo \$RESULT | grep -v grep | awk '{print \$2}'\`
  #设置连接master的同步相关信息
  SYNC_SQL="change master to master_host='\$MASTER_HOST',master_user='\$SLAVE_SYNC_USER',master_password='\$SLAVE_SYNC_PASSWORD',master_log_file='\$LOG_FILE_NAME',master_log_pos=\$LOG_FILE_POS;"
  #开启同步
  START_SYNC_SQL="start slave;"
  #查看同步状态
  STATUS_SQL="show slave status\G;"
  mysql -u"\$ADMIN_USER" -p"\$ADMIN_PASSWORD" -e "\$SYNC_SQL \$START_SYNC_SQL \$STATUS_SQL"
EOF

启动mysql-slave

docker run --name mysql-slave --network mysql -v ${PWD}/init/slave:/docker-entrypoint-initdb.d -e SLAVE_SYNC_USER="sync_root" -e SLAVE_SYNC_PASSWORD="sync_123456" -e MASTER_HOST="10.10.10.10" -e MYSQL_ROOT_PASSWORD="123456" -e ADMIN_USER="root" -e ADMIN_PASSWORD="123456" -d mysql:8.0.13 --server-id=2 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

查看日志,如果出现以下情况,等待一会儿,直到后续日志打印出同步信息即可

#查看日志
docker logs -f mysql-slave

docker篇-(docker-compose搭建mysql高可用主从集群)_第8张图片
同步信息如下
在这里插入图片描述
开启同步成功如下图
docker篇-(docker-compose搭建mysql高可用主从集群)_第9张图片

测试同步数据

1.进入mysql-master,创建一个数据库

docker exec -ti mysql-master bash
mysql -uroot -p123456
CREATE DATABASE `test-master`;
SHOW DATABASES;

docker篇-(docker-compose搭建mysql高可用主从集群)_第10张图片
2.进入mysql-slave,查看同步情况

docker exec -ti mysql-slave bash
mysql -uroot -p123456
SHOW DATABASES;

docker篇-(docker-compose搭建mysql高可用主从集群)_第11张图片

使用docker-compose,实现一键部署一主二从

在执行此脚本之前,请删除之前创建的mysql-master mysql-slave容器,以及mysql网卡

docker rm -f mysql-master
docker rm -f mysql-slave
docker network rm mysql

编写docker-compose.yml文件

version: '3'
services:
  mysql-master:
    image: mysql:8.0.13
    container_name: mysql-master
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MASTER_SYNC_USER: "sync_admin" #设置脚本中定义的用于同步的账号
      MASTER_SYNC_PASSWORD: "123456" #设置脚本中定义的用于同步的密码
      ADMIN_USER: "root" #当前容器用于拥有创建账号功能的数据库账号
      ADMIN_PASSWORD: "123456"
      ALLOW_HOST: "10.10.%.%" #允许同步账号的host地址
      TZ: "Asia/Shanghai" #解决时区问题
    networks:
      mysql:
        ipv4_address: "10.10.10.10" #固定ip,因为从库在连接master的时候,需要设置host
    volumes:
    - ./init/master:/docker-entrypoint-initdb.d #挂载master脚本
    command:
    -  "--server-id=1"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
    -  "--log-bin=mysql-bin"
    -  "--sync_binlog=1"
  mysql-slave1:
    image: mysql:8.0.13
    container_name: mysql-slave1
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      SLAVE_SYNC_USER: "sync_admin" #用于同步的账号,由master创建
      SLAVE_SYNC_PASSWORD: "123456"
      ADMIN_USER: "root"
      ADMIN_PASSWORD: "123456"
      MASTER_HOST: "10.10.10.10" #master地址,开启主从同步需要连接master
      TZ: "Asia/Shanghai" #设置时区
    networks:
    - mysql
    volumes:
    - ./init/slave:/docker-entrypoint-initdb.d #挂载slave脚本
    command:
    -  "--server-id=2"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
  mysql-slave2:
    image: mysql:8.0.13
    container_name: mysql-slave2
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      SLAVE_SYNC_USER: "sync_admin"
      SLAVE_SYNC_PASSWORD: "123456"
      ADMIN_USER: "root"
      ADMIN_PASSWORD: "123456"
      MASTER_HOST: "10.10.10.10"
      TZ: "Asia/Shanghai"
    networks:
    - mysql
    volumes:
    - ./init/slave:/docker-entrypoint-initdb.d
    command: #这里需要修改server-id,保证每个mysql容器的server-id都不一样
    -  "--server-id=3"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
networks:
  mysql:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: "10.10.0.0/16"

运行docker-compose.yaml

当前目录如下
docker篇-(docker-compose搭建mysql高可用主从集群)_第12张图片
运行情况如下
在这里插入图片描述

查看三台容器的日志

  • mysql-master

docker logs -f mysql-master

docker篇-(docker-compose搭建mysql高可用主从集群)_第13张图片

  • mysql-slave1

docker logs -f mysql-slave1

docker篇-(docker-compose搭建mysql高可用主从集群)_第14张图片

  • mysql-slave2

docker logs -f mysql-slave2

docker篇-(docker-compose搭建mysql高可用主从集群)_第15张图片

测试数据同步

  • mysql-master

创建数据库,数据表,并插入测试数据

docker exec -ti mysql-master bash
mysql -uroot -p123456
CREATE DATABASE `sync-data`;
USE `sync-data`;
CREATE TABLE `sync-data`(
id INT(10) AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL DEFAULT '' COMMENT '名称'
) ENGINE=INNODB;
INSERT INTO `sync-data`(`name`) VALUES('zhangsan'),('lisi');

docker篇-(docker-compose搭建mysql高可用主从集群)_第16张图片

  • mysql-slave1

进入mysql-slave1,查看数据同步情况

docker exec -ti mysql-slave1 bash
mysql -uroot -p123456
SELECT * FROM `sync-data`.`sync-data`;

docker篇-(docker-compose搭建mysql高可用主从集群)_第17张图片

  • mysql-slave2

进入mysql-slave2,查看数据同步情况

docker exec -ti mysql-slave2 bash
mysql -uroot -p123456
SELECT * FROM `sync-data`.`sync-data`;

docker篇-(docker-compose搭建mysql高可用主从集群)_第18张图片

加入nginx,实现slave的负载均衡

创建nginx负责均衡的配置文件

这里使用tcp代理,需要开启nginx的stream支持

  • 创建nginx.conf,开启stream支持

cat > nginx.conf <<EOF
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}

# 添加stream模块,实现tcp反向代理
stream {
    include /opt/nginx/stream/conf.d/*.conf; #加载 /opt/nginx/stream/conf.d目录下面的所有配置文件
}
EOF
  • 编写mysql.conf

mkdir -p conf.d/stream
cat > conf.d/stream/mysql.conf <<EOF
proxy_timeout 30m;
upstream mysql-slave-cluster{
  #docker-compose.yml里面会配置固定mysql-slave的ip地址,这里就填写固定的ip地址
  server 10.10.10.20:3306 weight=1;
  server 10.10.10.30:3306 weight=1 backup; #备用数据库,当上面的数据库挂掉之后,才会使用此数据库,也就是如果上面的数据库没有挂,则所有的流量都很转发到上面的主库
}
server {
  listen  0.0.0.0:3307;
  proxy_pass mysql-slave-cluster;
}
EOF

修改docker-compose.yml

version: '3'
services:
  mysql-slave-lb:
    image: nginx:alpine
    container_name: mysql-slave-lb
    ports:
    - 3307:3307
    volumes:
    - ./conf.d/stream:/opt/nginx/stream/conf.d
    - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
    - mysql
    depends_on:
    - mysql-master
    - mysql-slave1
    - mysql-slave2
  mysql-master:
    image: mysql:8.0.13
    container_name: mysql-master
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MASTER_SYNC_USER: "sync_admin" #设置脚本中定义的用于同步的账号
      MASTER_SYNC_PASSWORD: "123456" #设置脚本中定义的用于同步的密码
      ADMIN_USER: "root" #当前容器用于拥有创建账号功能的数据库账号
      ADMIN_PASSWORD: "123456"
      ALLOW_HOST: "10.10.%.%" #允许同步账号的host地址
      TZ: "Asia/Shanghai" #解决时区问题
    ports:
    - 3306:3306
    networks:
      mysql:
        ipv4_address: "10.10.10.10" #固定ip,因为从库在连接master的时候,需要设置host
    volumes:
    - ./init/master:/docker-entrypoint-initdb.d #挂载master脚本
    command:
    -  "--server-id=1"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
    -  "--log-bin=mysql-bin"
    -  "--sync_binlog=1"
  mysql-slave1:
    image: mysql:8.0.13
    container_name: mysql-slave1
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      SLAVE_SYNC_USER: "sync_admin" #用于同步的账号,由master创建
      SLAVE_SYNC_PASSWORD: "123456"
      ADMIN_USER: "root"
      ADMIN_PASSWORD: "123456"
      MASTER_HOST: "10.10.10.10" #master地址,开启主从同步需要连接master
      TZ: "Asia/Shanghai" #设置时区
    networks:
     mysql:
       ipv4_address: "10.10.10.20" #固定ip
    volumes:
    - ./init/slave:/docker-entrypoint-initdb.d #挂载slave脚本
    command:
    -  "--server-id=2"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
  mysql-slave2:
    image: mysql:8.0.13
    container_name: mysql-slave2
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      SLAVE_SYNC_USER: "sync_admin"
      SLAVE_SYNC_PASSWORD: "123456"
      ADMIN_USER: "root"
      ADMIN_PASSWORD: "123456"
      MASTER_HOST: "10.10.10.10"
      TZ: "Asia/Shanghai"
    networks:
      mysql:
        ipv4_address: "10.10.10.30" #固定ip
    volumes:
    - ./init/slave:/docker-entrypoint-initdb.d
    command: #这里需要修改server-id,保证每个mysql容器的server-id都不一样
    -  "--server-id=3"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
networks:
  mysql:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: "10.10.0.0/16"

执行docker-compose

当前目录如下
docker篇-(docker-compose搭建mysql高可用主从集群)_第19张图片

# 停掉之前启动的的容器
docker-compose down
#启动
docker-compose up -d

确保mysql-slave mysql-slave2的同步状态都是yes或者Connection,如果不是,请停掉容器,重新启动
如果是Connection状态,请等待片刻进入容器登录mysql重新查询状态,直到确认是Yes即可
查询状态的命令 show slave status\G
docker篇-(docker-compose搭建mysql高可用主从集群)_第20张图片

使用navicat连接从库

docker篇-(docker-compose搭建mysql高可用主从集群)_第21张图片

在mysql-master中创建测试数据,并进入navicat查看情况

1.插入数据

docker exec -ti mysql-master bash
mysql -uroot -p123456
CREATE DATABASE `sync-data`;
USE `sync-data`;
CREATE TABLE `sync-data`(
id INT(10) AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL DEFAULT '' COMMENT '名称'
) ENGINE=INNODB;
INSERT INTO `sync-data`(`name`) VALUES('zhangsan1'),('lisi1');

2.进入navicat查看数据如下
docker篇-(docker-compose搭建mysql高可用主从集群)_第22张图片

写在最后

这里讲述了如何手动搭建mysql主从,如何通过脚本一键的方式搭建主从,然后这里可以告诉大家,在使用脚本的方式搭建主从,有很多扩展性,如实现主主双写同步,多主多从集群方式,还可以加入检查脚本,实时检测同步情况,实现重连等等

你可能感兴趣的:(docker,mysql,docker,docker-compose,centos)