Docker 搭建 MySQL 主从服务实战操作详解
适用版本:MySQL 8.0+、Docker 20.10+
前言
在高可用、读写分离、数据备份等场景中,MySQL 主从复制(Master-Slave Replication)是基础且关键的技术。本文将通过 Docker 容器化方式,手把手教你搭建一套完整的 MySQL 主从复制环境,涵盖网络配置、权限设置、GTID 启用、复制启动与验证等细节,确保每一步都清晰可复现。
一、准备工作
1.1 环境要求
- 操作系统:Linux / macOS / Windows(WSL2 推荐)
- Docker 已安装并正常运行
- 至少 2GB 可用内存(主从各需约 512MB~1GB)
- 端口未被占用(主库 3307,从库 3308)
⚠️ 注意:为避免与本地 MySQL 冲突,本文使用非默认端口。
1.2 规划架构
| 角色 | 容器名 | IP 地址(自定义网络) | 端口映射 | 数据目录 |
|---|---|---|---|---|
| 主库 | mysql-master | 172.20.0.10 | 3307 | ./master/data |
| 从库 | mysql-slave | 172.20.0.11 | 3308 | ./slave/data |
我们将创建一个自定义 Docker 网络 mysql-net,确保容器间可通过固定 IP 通信。
二、创建自定义网络
bash
docker network create --driver bridge --subnet=172.20.0.0/24 mysql-net
验证网络:
bash
docker network inspect mysql-net
应看到 "Subnet": "172.20.0.0/24"。
三、准备配置文件
3.1 创建项目目录结构
bash
mkdir -p mysql-replication/{master,slave}/{conf,data}
cd mysql-replication
最终目录结构如下:
mysql-replication/
├── master/
│ ├── conf/
│ │ └── my.cnf
│ └── data/
└── slave/
├── conf/
│ └── my.cnf
└── data/
3.2 配置主库 my.cnf(master/conf/my.cnf)
ini
[mysqld]
# 基础设置
server-id = 1
port = 3306
bind-address = 0.0.0.0
datadir = /var/lib/mysql
socket = /var/run/mysqld/mysqld.sock
# 复制相关
log-bin = mysql-bin
binlog_format = ROW
binlog_expire_logs_seconds = 604800 # 7天过期
gtid_mode = ON
enforce_gtid_consistency = ON
# 其他优化(可选)
max_connections = 200
innodb_buffer_pool_size = 256M
✅ 关键点:
server-id必须唯一(主=1,从≠1)- 启用
log-bin是主库必备- GTID 模式简化复制管理,推荐开启
3.3 配置从库 my.cnf(slave/conf/my.cnf)
ini
[mysqld]
server-id = 2
port = 3306
bind-address = 0.0.0.0
datadir = /var/lib/mysql
socket = /var/run/mysqld/mysqld.sock
# 从库也需要启用 binlog(便于级联或故障切换)
log-bin = mysql-bin
relay-log = relay-bin
read_only = ON
gtid_mode = ON
enforced_gtid_consistency = ON
# 其他
max_connections = 200
innodb_buffer_pool_size = 256M
⚠️ 注意:
read_only = ON防止从库被误写(但 SUPER 权限用户仍可写)
四、启动 MySQL 主从容器
4.1 启动主库容器
bash
docker run -d \
--name mysql-master \
--network mysql-net \
--ip 172.20.0.10 \
-p 3307:3306 \
-v $(pwd)/master/conf/my.cnf:/etc/mysql/my.cnf:ro \
-v $(pwd)/master/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=Root@123456 \
--restart=unless-stopped \
mysql:8.0
4.2 启动从库容器
bash
docker run -d \
--name mysql-slave \
--network mysql-net \
--ip 172.20.0.11 \
-p 3308:3306 \
-v $(pwd)/slave/conf/my.cnf:/etc/mysql/my.cnf:ro \
-v $(pwd)/slave/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=Root@123456 \
--restart=unless-stopped \
mysql:8.0
🔍 参数说明:
-v ...:ro:配置文件只读挂载--ip:指定固定 IP,便于从库连接主库--restart=unless-stopped:容器自动重启
4.3 等待容器初始化完成
bash
# 查看日志,确认无报错
docker logs -f mysql-master
docker logs -f mysql-slave
等待出现 mysqld: ready for connections 即可继续。
五、配置主库复制账户
5.1 进入主库容器
bash
docker exec -it mysql-master mysql -uroot -p
# 输入密码:Root@123456
5.2 创建用于复制的专用用户
sql
CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
✅ 安全建议:
- 不要使用 root 用户做复制
- 密码强度足够
- 可限制 IP(如
'repl'@'172.20.0.11')
5.3 查看主库状态(记录 GTID 或 binlog 位置)
sql
SHOW MASTER STATUS\G
输出示例:
*************************** 1. row ***************************
File: mysql-bin.000002
Position: 156
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:1-5
📌 在 GTID 模式下,我们主要关注
Executed_Gtid_Set,传统模式才需File + Position。
六、配置从库连接主库
6.1 进入从库容器
bash
docker exec -it mysql-slave mysql -uroot -p
# 密码:Root@123456
6.2 设置主从关系(GTID 模式)
sql
CHANGE MASTER TO
MASTER_HOST='172.20.0.10',
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='Repl@123456',
MASTER_AUTO_POSITION=1; -- 关键!启用 GTID 自动定位
✅
MASTER_AUTO_POSITION=1表示使用 GTID 自动同步,无需手动指定 binlog 文件和位置。
6.3 启动从库复制线程
sql
START SLAVE;
6.4 检查复制状态
sql
SHOW SLAVE STATUS\G
重点关注以下字段:
| 字段 | 正常值 |
|---|---|
Slave_IO_Running |
Yes |
Slave_SQL_Running |
Yes |
Seconds_Behind_Master |
0(或很小) |
Last_IO_Error / Last_SQL_Error |
(空) |
❌ 若出现错误,需根据具体信息排查(常见:网络不通、账号密码错误、GTID 不一致等)
七、验证主从复制
7.1 在主库创建测试数据库和表
sql
-- 主库执行
CREATE DATABASE test_replication;
USE test_replication;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');
7.2 在从库查询数据
sql
-- 从库执行
SHOW DATABASES;
USE test_replication;
SELECT * FROM users;
应看到与主库完全一致的数据。
✅ 成功!主从复制已生效。
八、常见问题排查
8.1 从库无法连接主库
- 检查
docker network inspect mysql-net确认 IP 正确 - 在从库容器内
ping 172.20.0.10测试连通性 - 检查主库是否监听
0.0.0.0(非127.0.0.1)
8.2 复制线程未启动
- 执行
STOP SLAVE; START SLAVE;重启 - 查看
SHOW SLAVE STATUS中的错误信息
8.3 GTID 不一致导致复制中断
- 若从库有独立写入(不推荐),可能导致 GTID 冲突
- 解决方案:重做从库(清空数据目录,重新配置)
九、停止与清理
bash
# 停止并删除容器
docker stop mysql-master mysql-slave
docker rm mysql-master mysql-slave
# 删除数据(谨慎!)
rm -rf master/data slave/data
# 删除网络
docker network rm mysql-net
十、总结
通过本文,你已掌握:
✅ 使用 Docker 快速部署 MySQL 主从
✅ 配置 GTID 模式实现自动位点同步
✅ 创建专用复制账号提升安全性
✅ 验证复制效果并排查常见问题
💡 进阶建议:
- 结合
docker-compose.yml管理多容器- 添加监控(如 Prometheus + mysqld_exporter)
- 配置半同步复制提升数据一致性
附录:docker-compose.yml 示例(可选)
yaml
version: '3.8'
services:
mysql-master:
image: mysql:8.0
container_name: mysql-master
networks:
mysql-net:
ipv4_address: 172.20.0.10
ports:
- "3307:3306"
volumes:
- ./master/conf/my.cnf:/etc/mysql/my.cnf:ro
- ./master/data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: Root@123456
restart: unless-stopped
mysql-slave:
image: mysql:8.0
container_name: mysql-slave
networks:
mysql-net:
ipv4_address: 172.20.0.11
ports:
- "3308:3306"
volumes:
- ./slave/conf/my.cnf:/etc/mysql/my.cnf:ro
- ./slave/data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: Root@123456
restart: unless-stopped
networks:
mysql-net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
使用命令:
bash
docker-compose up -d
🎉 恭喜你,成功搭建了高可用的 MySQL 主从架构!如有疑问,欢迎交流。