11、Docker Compose 配置Mysql主从(单虚拟机)
🚀 Docker Compose 配置一主两从的 MySQL 主从复制集群(含详解与实战)
标签:Docker | MySQL | 主从复制 | Compose | 分布式 | 架构搭建
难度:🌟🌟🌟 中等
适用人群:后端开发、架构师、运维工程师
📚 目录导航
- 一、前言
- 二、MySQL 主从复制原理简述
- 三、项目目录结构
- 四、docker-compose.yml 配置详解
- 五、my.cnf 主从配置文件
- 六、初始化 SQL 创建复制用户
- 七、启动服务与配置主从复制
- 八、主从复制验证
- 九、常见问题排查
- 十、总结
一、前言
在高并发环境下,为了解决 MySQL 单点瓶颈,常见的做法是配置主从复制,实现读写分离,提高系统性能与可用性。本文通过 Docker Compose 一键搭建 一主两从 的 MySQL 主从集群,并手动配置复制关系,适合本地开发和测试环境快速模拟分布式数据库结构。
二、MySQL 主从复制原理简述
MySQL 主从复制是一种异步复制机制:
- 主库将数据更改写入 二进制日志(binlog)
- 从库通过 IO 线程 拉取主库的 binlog
- 从库的 SQL 线程 将 binlog 应用到本地数据库
主从结构:
+---------+ +---------+ +---------+
| Master | ---> | Slave1 | ---> | Slave2 |
+---------+ +---------+ +---------+
写操作 读操作 读操作
三、项目目录结构
mysql-replication/
├── docker-compose.yml
├── master/
│ └── my.cnf
│ └── init.sql
├── slave1/
│ └── my.cnf
├── slave2/
│ └── my.cnf
四、docker-compose.yml 配置详解
version: '3.9'services:master:image: mysql:8.0container_name: mysql-masterrestart: alwaysports:- "3307:3306"environment:MYSQL_ROOT_PASSWORD: rootvolumes:- ./master/my.cnf:/etc/mysql/my.cnf- ./master/init.sql:/docker-entrypoint-initdb.d/init.sqlnetworks:- mysql-clusterslave1:image: mysql:8.0container_name: mysql-slave1restart: alwaysports:- "3308:3306"environment:MYSQL_ROOT_PASSWORD: rootvolumes:- ./slave1/my.cnf:/etc/mysql/my.cnfnetworks:- mysql-clusterdepends_on:- masterslave2:image: mysql:8.0container_name: mysql-slave2restart: alwaysports:- "3309:3306"environment:MYSQL_ROOT_PASSWORD: rootvolumes:- ./slave2/my.cnf:/etc/mysql/my.cnfnetworks:- mysql-clusterdepends_on:- masternetworks:mysql-cluster:driver: bridge
📌 配置项详解
配置项 | 说明 |
---|---|
version | Compose 文件格式版本 |
services | 定义每个服务(容器) |
image | 使用的 MySQL 镜像版本 |
container_name | 自定义容器名称,便于主从识别 |
restart | 容器异常自动重启 |
ports | 映射到主机端口 |
environment | 设置环境变量(如 root 密码) |
volumes | 挂载本地配置或初始化 SQL 脚本 |
depends_on | 声明依赖启动顺序 |
networks | 配置服务所属网络,实现容器互通 |
五、my.cnf 主从配置文件
master/my.cnf
[mysqld]
server-id=1 # 唯一标识主库,不能与从库重复
log-bin=mysql-bin # 启用二进制日志,用于复制
binlog-format=ROW # 使用行级复制格式,精确且安全
gtid_mode=ON # 开启 GTID 复制模式,简化复制管理
enforce_gtid_consistency=ON # 确保 GTID 复制的一致性
log_slave_updates=ON # 允许从库写日志,支持多级复制
slave1/my.cnf
[mysqld]
server-id=2 # 唯一标识,从库1
relay-log=relay-bin # 中继日志文件
read_only=ON # 从库只读,避免写操作
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
slave2/my.cnf
[mysqld]
server-id=3 # 唯一标识,从库2
relay-log=relay-bin
read_only=ON
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
六、初始化 SQL 创建复制用户(master/init.sql)
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
这三条 SQL 命令是用于设置 MySQL 主从复制(Replication)所需的账号权限的,逐条解释如下:
✅ 第一句:
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'replpass';
意思是:
- 创建一个名为
repl
的用户。 @'%'
表示该用户可以从任何主机连接(即 slave 容器连接 master)。- 使用
mysql_native_password
插件进行身份验证(兼容性最好,尤其在 MySQL 8 中设置复制用户建议指定)。 - 密码是
'replpass'
。
🧠 补充说明:
MySQL 8.0 开始默认的密码插件是 caching_sha2_password
,但它在某些客户端连接或复制场景下可能不兼容,因此常推荐显式指定 mysql_native_password
。
✅ 第二句:
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
这句是给刚创建的用户 repl
授予 复制权限:
REPLICATION SLAVE
是允许该用户执行CHANGE MASTER TO
和START SLAVE
等操作。ON *.*
表示作用于所有数据库。
✅ 第三句:
FLUSH PRIVILEGES;
意思是让权限修改 立即生效(在 MySQL 中大多数情况下并非必须,但是一种安全的做法)。
📦 总结一下这三行是干嘛的?
这是在主库(mysql-master
)中创建一个能被从库(mysql-slave
)连接的专用账号 repl
,并授予它复制权限。
从库使用这个账号去主库“同步 binlog 事件”,完成数据复制。
👇 你后续会在从库执行如下命令使用这个账号:
CHANGE MASTER TOMASTER_HOST='mysql-master',MASTER_USER='repl',MASTER_PASSWORD='replpass',MASTER_LOG_FILE='xxx',MASTER_LOG_POS=xxx;
七、启动服务与配置主从复制
1️⃣ 启动集群
docker compose up -d
2️⃣ 查看 master 的 binary log 位置
docker exec -it mysql-master mysql -uroot -proot -e "SHOW MASTER STATUS\G"
得到
File
和Position
信息,例如:mysql-bin.000003
,Position: 197
3️⃣ 分别配置 slave1 和 slave2 复制主库
CHANGE MASTER TOMASTER_HOST='mysql-master',MASTER_USER='repl',MASTER_PASSWORD='replpass',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=197;START SLAVE;
执行方式(示例 slave1):
docker exec -it mysql-slave1 mysql -uroot -proot -e "CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=197; START SLAVE;"
执行方式(示例 slave2):
docker exec -it mysql-slave2 mysql -uroot -proot -e "CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repl', MASTER_PASSWORD='replpass', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=197; START SLAVE;"
如果是在三台虚拟机之间配置 MySQL 主从,只需要在从库上将 MASTER_HOST 设置为 主库所在虚拟机的 IP 地址 即可完成跨虚拟机的主从复制配置。三台虚拟机需要 能互相 ping 通、端口开放(通常是 3306)。
🔍 详细说明:
配置项 | 说明 |
---|---|
MASTER_HOST | 主库的 真实 IP 地址,不能写 localhost 或容器名,除非是同一个网络。 |
MASTER_USER | 主库中授权用于复制的账号,权限通常为 REPLICATION SLAVE 。 |
MASTER_PASSWORD | 对应账号的密码。 |
MASTER_LOG_FILE | 主库当前二进制日志文件名(通过 SHOW MASTER STATUS; 获取)。 |
MASTER_LOG_POS | 当前日志的偏移量位置。 |
八、主从复制验证
在 mysql-master
中插入数据:
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE user (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO user VALUES (1, 'Tom');
然后在 slave1、slave2 查询:
SELECT * FROM testdb.user;
输出一致即说明主从同步成功。
九、常见问题排查
问题 | 解决方案 |
---|---|
getaddrinfo for mysql-master failed | 检查 container_name 是否设置为 mysql-master |
Slave_IO_Running: No | 检查 MASTER_LOG_FILE 和 POS 是否正确 |
Access denied for user 'repl' | 检查 repl 用户权限,是否使用了 mysql_native_password |
十、总结
本文完整介绍了如何通过 Docker Compose 一键构建一主两从的 MySQL 主从复制集群,支持读写分离与高可用架构演练。你可以在此基础上扩展:
- 增加 MySQL Router 或 ProxySQL 实现自动读写分离
- 接入 Spring Boot 实现主从读写动态切换
- 增加备份 + 监控模块(如 Prometheus + Grafana)
📌 点赞 + 收藏 + 关注不迷路!