基于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 默认已装)
相关推荐
迷糊小面包1 小时前
Docker Hadopp集群版部署搭建及常规问题解疑
运维·docker·容器
烁3472 小时前
Docker
运维·docker·容器
健康平安的活着3 小时前
mysql中数据库脚本太大,通过脚本命令修改db名称
数据库·mysql
网络中的夜鹰3 小时前
轩辕镜像一键安装Docker和Docker Compose脚本
运维·docker·容器
minji...4 小时前
MySQL数据库 (八) MySQL表的基本查询(下),truncate、group by、聚合函数、分组聚合统计
数据库·mysql·聚合函数·update·分组聚合统计
梦想的颜色5 小时前
从零入门:Docker在Ubuntu上的安装、使用与主流镜像仓库实战(Java/Go/MySQL/PostgreSQL/MongoDB/Nginx
java·ubuntu·docker
乐世东方客5 小时前
备份脚本记录(binlog文件+mysql+mongo)
android·数据库·mysql
暴力求解5 小时前
MySQL---数据类型
数据库·mysql
java知路6 小时前
centos euler离线下载docker镜像
linux·docker·centos
江湖有缘6 小时前
Docker部署HamsterBase Tasks任务管理工具
运维·docker·容器