使用docker-compose搭建mysql主从复制

使用docker-compose搭建mysql主从

  • 写在前面
  • 编写master.sh脚本
  • 编写slave.sh脚本
  • 编写docker-compose.yml脚本
  • 启动准备
    • 最终结构
    • 执行脚本
  • 测试阶段
    • 主从同步效果
    • 主从环境重启
    • 容器被删除,重新启动
    • 从节点关闭,主节点继续写入数据
    • 从节点删除,主节点继续写入数据,从节点重新创建
  • 写在后面

写在前面

写此博客,主要是简化mysql主从搭建,同时给需要学习mysql主从的同学一个现成的环境。

编写master.sh脚本

此脚本主要是根据环境变量,创建出用于主从同步的用户。关于为什么要创建出master,slave脚本,是为了区分master和slave环境,因为只要把sql和sh文件放到master目录下面,master在第一次初始化的时候,会自动执行里面的文件内容

mkdir -p init init/master init/slave
cat > init/master/master.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 SELECT,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

编写slave.sh脚本

slave主要是去master查询最新的pos位置和binlog文件名称,然后创建同步需要的相关信息,然后执行start 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:-%}"
#连接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,get_master_public_key=1;"
#开启同步
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

编写docker-compose.yml脚本

version: '3'
services:
  master:
    image: mysql:8.0.28
    container_name: mysql-master
    ports:
    - '3306:3306'
    restart: always
    hostname: mysql-master
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MASTER_SYNC_USER: "sync"
      MASTER_SYNC_PASSWORD: "123456"
      ADMIN_USER: "root"
      ADMIN_PASSWORD: "123456"
      TZ: "Asia/Shanghai"
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: 50m
    healthcheck:
      test: ["CMD","mysqladmin","-uroot","-p$${MYSQL_ROOT_PASSWORD}","ping","-h","localhost"]
      timeout: 2s
      interval: 10s
      retries: 5
      start_period: 5s
    logging:
      options:
        max-file: '1'
        max-size: '128k'
    command:
    -  "--server-id=1"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
    -  "--log-bin=mysql-bin"
    -  "--sync_binlog=1"
    -  "--binlog-ignore-db=mysql"
    -  "--binlog-ignore-db=sys"
    -  "--binlog-ignore-db=performance_schema"
    -  "--binlog-ignore-db=information_schema"
    -  "--sql_mode=NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT,ANSI_QUOTES"
    volumes:
    - ./init/master:/docker-entrypoint-initdb.d
    - ./data/master:/var/lib/mysql
  slave:
    image: mysql:8.0.28
    container_name: mysql-slave
    ports:
    - '3307:3306'
    restart: always
    hostname: mysql-slave
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      SLAVE_SYNC_USER: "sync"
      SLAVE_SYNC_PASSWORD: "123456"
      ADMIN_USER: "root"
      ADMIN_PASSWORD: "123456"
      MASTER_HOST: "mysql-master"
      TZ: "Asia/Shanghai"
    healthcheck: 
      test: ["CMD","mysqladmin","-uroot","-p$${MYSQL_ROOT_PASSWORD}","ping","-h","localhost"]
      timeout: 2s
      interval: 10s
      retries: 5
      start_period: 5s
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: 50m
    logging:
      options:
        max-file: '1'
        max-size: '128k'
    depends_on:
      master:
        condition: service_healthy
    command:
    -  "--server-id=2"
    -  "--character-set-server=utf8mb4"
    -  "--collation-server=utf8mb4_unicode_ci"
    -  "--sql_mode=NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT,ANSI_QUOTES"
    volumes:
    - ./init/slave:/docker-entrypoint-initdb.d
    - ./data/slave:/var/lib/mysql

启动准备

最终结构

根据上面的脚本,执行之后,应该会是如下结构
使用docker-compose搭建mysql主从复制_第1张图片

执行脚本

docker-compose up -d

执行之后的效果
在这里插入图片描述

docker logs -f mysql-slave

查看mysql-slave日志,看到以下两个yes,就代表成功了
使用docker-compose搭建mysql主从复制_第2张图片

测试阶段

连接信息
使用docker-compose搭建mysql主从复制_第3张图片
使用docker-compose搭建mysql主从复制_第4张图片

主从同步效果

3307是从节点
使用docker-compose搭建mysql主从复制_第5张图片

创建数据库,可以看到,在主节点创建数据库之后,从节点刷新就能看到
使用docker-compose搭建mysql主从复制_第6张图片

创建表及添加数据测试
使用docker-compose搭建mysql主从复制_第7张图片
使用docker-compose搭建mysql主从复制_第8张图片

主从环境重启

docker-compose restart

在这里插入图片描述
重新连接数据库,查看从节点同步状态

SHOW SLAVE STATUS;

可以看到,重启之后,同步也是正常的
使用docker-compose搭建mysql主从复制_第9张图片

当修改数据和新增数据,也是可以正常同步
使用docker-compose搭建mysql主从复制_第10张图片
使用docker-compose搭建mysql主从复制_第11张图片

容器被删除,重新启动

可以看到,容器已经被删除了,数据库也无法正常连接
使用docker-compose搭建mysql主从复制_第12张图片
使用docker-compose搭建mysql主从复制_第13张图片
重启容器,查看同步状态,

docker-compose up -d

使用docker-compose搭建mysql主从复制_第14张图片
在从节点执行。可以看到,同步也是正常的

SHOW SLAVE STATUS;

使用docker-compose搭建mysql主从复制_第15张图片

验证同步效果.这里删除id=5的数据,新增id=7,9的数据
可以看到,也是正常同步的
使用docker-compose搭建mysql主从复制_第16张图片
使用docker-compose搭建mysql主从复制_第17张图片

从节点关闭,主节点继续写入数据

这里测试,当从节点被关闭,然后主节点继续写入数据,然后从节点启动

docker stop mysql-slave

在这里插入图片描述
主节点写入数据
这里将原本id=3的数据删除,修改id=7,9变为8,10,新增id=11的记录
使用docker-compose搭建mysql主从复制_第18张图片
启动从节点,并查看同步状态

docker start mysql-slave

在这里插入图片描述
可以看到,同步也是正常开启的
使用docker-compose搭建mysql主从复制_第19张图片
数据也是正常同步
使用docker-compose搭建mysql主从复制_第20张图片

从节点删除,主节点继续写入数据,从节点重新创建

docker rm -f mysql-slave

可以看到,从节点容器已经被删除,也无法正常连接
在这里插入图片描述
使用docker-compose搭建mysql主从复制_第21张图片

主节点操作数据
这里创建testa表,新增一些数据,test表删除id=10的数据,修改id=11的数据改为id=15
使用docker-compose搭建mysql主从复制_第22张图片
使用docker-compose搭建mysql主从复制_第23张图片
使用docker-compose搭建mysql主从复制_第24张图片
创建从节点
使用docker-compose搭建mysql主从复制_第25张图片
查看日志,可以看到,这里test.test这个表,id=11的数据重复了,这里我们登录从节点,将id=11的这条数据删除,然后重新开启同步
使用docker-compose搭建mysql主从复制_第26张图片
使用docker-compose搭建mysql主从复制_第27张图片
使用docker-compose搭建mysql主从复制_第28张图片
重新开启同步

STOP SLAVE;
START SLAVE;
SHOW SLAVE STATUS;

可以看到,这里是yes,这个时候我们再去看日志
使用docker-compose搭建mysql主从复制_第29张图片

可以看到,这里同步失败了,同时并没有提示我们是那条数据,所以我们不能通过删除或者修改数据来修复问题,因此我们需要将数据库删除,然后重新修改同步的pos位置信息,重新启动同步在这里插入图片描述

删除test数据库
使用docker-compose搭建mysql主从复制_第30张图片
修改pos信息,重新启动同步

STOP SLAVE;
RESET SLAVE;
CHANGE MASTER TO master_log_pos=0;
START SLAVE;
SHOW SLAVE STATUS;

使用docker-compose搭建mysql主从复制_第31张图片
可以看到,数据已经同步过来了
使用docker-compose搭建mysql主从复制_第32张图片
测试同步
使用docker-compose搭建mysql主从复制_第33张图片
使用docker-compose搭建mysql主从复制_第34张图片
使用docker-compose搭建mysql主从复制_第35张图片
使用docker-compose搭建mysql主从复制_第36张图片

写在后面

基于docker-compose搭建mysql主从已经结束,这里主要演示了如何一键搭建mysql主从,同时测试在各种环境下,还能保证主从同步。但是单主从同步肯定也无法满足企业的需求,有兴趣的同学可以研究一些主主双写同步,然后通过nginx搭建主备模式,达到高可用。当然,根据我的猜想,是可以实现的
文中一键搭建环境mysql主从复制脚本

你可能感兴趣的:(docker,mysql,docker,数据库)