基于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 默认已装)
相关推荐
invicinble3 小时前
对于Mysql深入理解
数据库·mysql
lightningyang4 小时前
DVWA 在 openEuler 系统的安装部署
docker·渗透测试·openeuler·dvwa·天枢一体化虚拟仿真靶场平台
霖霖总总5 小时前
[小技巧56]深入理解 MySQL 聚簇索引与非聚簇索引:原理、差异与实践
数据库·mysql
伐尘5 小时前
【MySQL】间隙锁 与 排他锁 的区别
数据库·mysql
快乐非自愿7 小时前
【面试题】MySQL 的索引类型有哪些?
数据库·mysql·面试
Ha_To7 小时前
2026.1.28 docker安装
运维·docker·容器
霖霖总总7 小时前
[小技巧55]深入解析数据库日志机制:逻辑日志、物理日志与物理逻辑日志在 MySQL InnoDB 中的实现
数据库·mysql
北极熊~~8 小时前
emqx持久化 Docker 容器中生成的数据并打包新镜像,迁移至新机器运行
运维·docker·容器
tomiatomia8 小时前
MinIO docker 部署使用的几个坑
运维·docker·容器
luoluoal10 小时前
基于python的人脸识别的酒店客房入侵检测系统(源码+文档)
python·mysql·django·毕业设计·源码