基于Docker的MySQL 主从复制(读写分离)

基于 Docker + Docker Compose

使用 GTID 自动定位(更可靠)

日志挂载到宿主机并自动保留 60 天

仅用于 开发/测试不可用于生产


docker安装可参照 day02 -- docker

第一步:创建项目目录

bash 复制代码
# 创建并进入项目目录
mkdir -p /opt/mysql-replication && cd /opt/mysql-replication

# 创建所需子目录
mkdir -p \
  data/{master,slave} \
  logs/{master,slave} \
  init \
  conf

第二步:创建配置文件

1. 主库配置 conf/master.cnf

bash 复制代码
cat > conf/master.cnf << 'EOF'
[mysqld]
server-id=1
log-bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON

# 日志设置
log_error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
general_log = OFF
EOF

2. 从库配置 conf/slave.cnf

bash 复制代码
cat > conf/slave.cnf << 'EOF'
[mysqld]
server-id=2
gtid_mode=ON
enforce_gtid_consistency=ON
read_only=ON

# 日志设置
log_error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
general_log = OFF
EOF

第三步:创建初始化 SQL 脚本

1. 主库初始化脚本 init/master.sql

bash 复制代码
cat > init/master.sql << 'EOF'
-- 创建复制专用用户(兼容 MySQL 8.0 客户端)
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'slavepass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
EOF

2. 从库初始化脚本 init/slave.sql

bash 复制代码
cat > init/slave.sql << 'EOF'
-- 安全停止旧复制(首次无影响)
STOP SLAVE;

-- 配置主从连接(使用 Docker 服务名)
CHANGE MASTER TO
  MASTER_HOST='mysql-master',
  MASTER_USER='repl',
  MASTER_PASSWORD='slavepass',
  MASTER_AUTO_POSITION=1;

-- 启动复制
START SLAVE;

-- 提示信息(日志可见)
SELECT 'Slave replication started.' AS Info;
EOF

第四步:创建 docker-compose.yml

bash 复制代码
cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  mysql-master:
    image: mysql:8.0
    container_name: mysql-master
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
    volumes:
      - ./data/master:/var/lib/mysql
      - ./init/master.sql:/docker-entrypoint-initdb.d/master.sql
      - ./conf/master.cnf:/etc/mysql/conf.d/master.cnf
      - ./logs/master:/var/log/mysql
    ports:
      - "33060:3306"
    networks:
      - mysql-net

  mysql-slave:
    image: mysql:8.0
    container_name: mysql-slave
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
    volumes:
      - ./data/slave:/var/lib/mysql
      - ./init/slave.sql:/docker-entrypoint-initdb.d/slave.sql
      - ./conf/slave.cnf:/etc/mysql/conf.d/slave.cnf
      - ./logs/slave:/var/log/mysql
    ports:
      - "33070:3306"
    depends_on:
      - mysql-master
    networks:
      - mysql-net

networks:
  mysql-net:
    driver: bridge
EOF

第五步:启动服务

bash 复制代码
# 启动容器(后台运行)
docker compose up -d

# 查看启动状态
docker compose ps

首次启动需 20~30 秒,请耐心等待 MySQL 初始化完成。


第六步:验证主从复制是否成功

1. 检查从库复制状态

bash 复制代码
docker exec -i mysql-slave mysql -uroot -prootpass -e "SHOW SLAVE STATUS\G" \
  | grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Master_Host"

正常输出应包含:

复制代码
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
        Seconds_Behind_Master: 0
                 Master_Host: mysql-master

2. 手动测试数据同步

bash 复制代码
# 在主库创建测试数据
docker exec -i mysql-master mysql -uroot -prootpass -e "
CREATE DATABASE IF NOT EXISTS test_replication;
USE test_replication;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');
"

# 在从库查询
docker exec -i mysql-slave mysql -uroot -prootpass -e "
SELECT * FROM test_replication.users;
"

应返回两条记录,说明同步成功!

上图中的警告是在命令行中直接使用了 -prootpass,这会导致密码可能被其他系统用户通过 ps 命令查看到,或者记录在 shell 历史中(密码泄露风险)。


第七步:配置日志自动清理(最多保留 60 天)

利用宿主机 logrotate 实现日志轮转与清理。

1. 获取当前项目绝对路径

bash 复制代码
PROJECT_PATH=$(pwd)
echo "项目路径: $PROJECT_PATH"

2. 创建 logrotate 配置文件

bash 复制代码
sudo tee /etc/logrotate.d/mysql-replication > /dev/null << EOF
${PROJECT_PATH}/logs/master/*.log
${PROJECT_PATH}/logs/slave/*.log
{
    daily
    missingok
    rotate 60
    compress
    delaycompress
    notifempty
    copytruncate
}
EOF

3. 验证配置(可选)

bash 复制代码
# 测试语法
sudo logrotate -d /etc/logrotate.d/mysql-replication

# 强制立即轮转一次(调试用)
sudo logrotate -f /etc/logrotate.d/mysql-replication

轮转后会在 logs/*/ 目录生成 .1.1.gz 等归档文件

系统每天自动运行,超过 60 天的日志将被自动删除


第八步:开发环境重置(谨慎操作!)

仅限本地开发!会清空所有数据和日志!

bash 复制代码
# 1. 停止并删除容器
docker compose down

# 2. 清空数据和日志
rm -rf data/master/* data/slave/* logs/master/* logs/slave/*

# 3. 重新启动
docker compose up -d

远程连接数据库需要安全组/防火墙开放33060,33070端口,用户名与密码如下:

用户名 密码 备注
root rootpass 主从库root用户
repl slavepass 从库复制主库的专用账号,此账号不能登录从库

第九步:常用操作命令速查

操作 命令
查看主库错误日志 tail -f logs/master/error.log
查看从库慢查询 tail -f logs/slave/slow.log
进入主库 CLI docker exec -it mysql-master mysql -uroot -prootpass
进入从库 CLI docker exec -it mysql-slave mysql -uroot -prootpass
重启服务 docker-compose restart
查看容器日志 docker logs mysql-slave

注意事项

  • 不要在生产环境使用 rm -rf data/ !生产环境应使用 RESET SLAVE ALL + 备份恢复。
  • 若从库无法连接主库,请检查:
    • MASTER_HOST 是否为 mysql-master(Docker 服务名)
    • 主库是否已创建 repl 用户且密码正确
    • 主从 gtid_mode 配置是否一致
  • 日志挂载依赖 logrotate,确保系统已安装(Ubuntu/Debian 默认已装)
相关推荐
m0_474606782 小时前
Linux安装docker教程
linux·运维·docker
神仙别闹2 小时前
基于QT(C++)+MySQL实现(窗体)学生信息管理系统
c++·qt·mysql
不会c嘎嘎2 小时前
MySQL 指南:全面掌握用户管理与权限控制
数据库·mysql
Jewel Q3 小时前
QEMU、KVM、Docker、K8s(Kubernetes)
docker·容器·kubernetes
李慕婉学姐3 小时前
【开题答辩过程】以《基于PHP的动漫社区的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
开发语言·mysql·php
学Linux的语莫3 小时前
prometheus、grafana的docker搭建
docker·容器·prometheus
lisanmengmeng3 小时前
zentao的prod环境升级(一)
linux·运维·数据库·docker·容器·禅道
それども3 小时前
insertOnDuplicateKey 和 upsert 区别
数据库·mysql
kkoral4 小时前
单机docker部署的redis sentinel,使用python调用redis,报错
redis·python·docker·sentinel