在微服务与持续集成环境中,把MySQL主从复制架构用容器方式部署,能够显著降低环境差异带来的故障率。通过合理的容器编排,我们可以让主库和从库使用同一套配置模板,仅在server-id等少数参数上有所区别,从而减少人为失误。下面介绍一套基于docker compose的实现方案。

一、为什么用容器编排做MySQL主从
过去在物理机或虚拟机上搭建主从,需要分别登录每台机器修改配置文件、重启服务、创建复制账号。流程繁琐且难以复用。容器编排把这些都声明在文本文件里,任何人拿到文件执行一条命令就能得到相同结构的集群。
另一个好处是隔离性。每个MySQL实例运行在自己的容器中,端口、数据卷、网络都通过编排文件限定,不会污染宿主机。当测试完毕,直接销毁容器即可,不会留下残余进程或文件。
二、编写docker compose编排文件
我们使用docker compose定义两个服务:mysql-master和mysql-slave。主库暴露3306端口,从库暴露3307。两者挂载不同的数据目录和配置目录。
version: '3.8'
services:
mysql-master:
image: mysql:8.0
container_name: mysql-master
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: demo
ports:
- "3306:3306"
volumes:
- ./master/my.cnf:/etc/mysql/conf.d/my.cnf
- master-data:/var/lib/mysql
networks:
- mysql-net
mysql-slave:
image: mysql:8.0
container_name: mysql-slave
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: demo
ports:
- "3307:3306"
volumes:
- ./slave/my.cnf:/etc/mysql/conf.d/my.cnf
- slave-data:/var/lib/mysql
networks:
- mysql-net
depends_on:
- mysql-master
volumes:
master-data:
slave-data:
networks:
mysql-net:
driver: bridge
上面的编排中,master和slave分别挂载了各自的my.cnf。通过depends_on保证从库在主库之后启动,但这并不等于主库已就绪,后面我们会用初始化脚本补齐。
三、主从配置文件与初始化脚本
主库配置需要开启二进制日志并设置唯一server-id。从库也要有唯一server-id且开启中继日志。下面给出主库my.cnf示例。
[mysqld] server-id=1 log-bin=mysql-bin binlog-format=ROW expire_logs_days=7
从库配置如下,注意server-id不能与主库相同:
[mysqld] server-id=2 relay-log=relay-bin read-only=1
为了让从库自动连接主库,我们准备一个初始化SQL脚本,在主库创建复制账号,并在从库执行CHANGE MASTER。可以把脚本挂到从库容器的/docker-entrypoint-initdb.d目录,但需注意主库必须已启动并创建好账号。更稳妥的做法是用一个等待脚本。
#!/bin/bash
# 等待主库可用
until mysql -h mysql-master -uroot -prootpass -e "SELECT 1"; do
sleep 3
done
# 在主库创建复制用户(若未创建)
mysql -h mysql-master -uroot -prootpass <<EOF
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
EOF
# 获取主库状态
MASTER_STATUS=$(mysql -h mysql-master -uroot -prootpass -e "SHOW MASTER STATUSG")
BINLOG_FILE=$(echo "$MASTER_STATUS" | grep File | awk '{print $2}')
BINLOG_POS=$(echo "$MASTER_STATUS" | grep Position | awk '{print $2}')
# 配置从库
mysql -uroot -prootpass <<EOF
CHANGE MASTER TO
MASTER_HOST='mysql-master',
MASTER_USER='repl',
MASTER_PASSWORD='replpass',
MASTER_LOG_FILE='$BINLOG_FILE',
MASTER_LOG_POS=$BINLOG_POS;
START SLAVE;
EOF
这段脚本先轮询主库连通性,再确保复制账号存在,最后读取主库binlog坐标并启动从库复制线程。把它作为从库容器的启动命令或初始化任务,可以避免手动操作的时序问题。
四、数据持久化与网络互通
容器编排中如果不挂卷,容器删除后数据就丢失了。我们在compose里声明了named volume,分别对应master-data和slave-data,MySQL的数据目录/var/lib/mysql会写入其中,重启容器数据仍在。
网络方面,两个服务都加入mysql-net桥接网络,从库可以用服务名mysql-master作为主机名访问主库。这与 Kubernetes 中的 Service 名解析类似,不需要知道具体IP。若需要在宿主机连接,可通过ports映射的3306与3307端口。
| 项目 | 主库 | 从库 |
|---|---|---|
| 容器名 | mysql-master | mysql-slave |
| server-id | 1 | 2 |
| 对外端口 | 3306 | 3307 |
| 数据卷 | master-data | slave-data |
五、验证复制状态
启动后进入从库容器,执行SHOW SLAVE STATUS检查关键字段。Slave_IO_Running和Slave_SQL_Running都应为Yes,Seconds_Behind_Master表示延迟秒数。
SHOW SLAVE STATUSG -- 关注以下两行 -- Slave_IO_Running: Yes -- Slave_SQL_Running: Yes -- Seconds_Behind_Master: 0
我们可以在主机上往主库插入一条数据,随后查从库是否同步。如果同步正常,说明编排成功。若出现连接错误,优先检查复制账号权限、主库防火墙以及my.cnf中bind-address是否限制为127.0.0.1。
注意:MySQL 8.0默认认证插件为caching_sha2_password,部分旧客户端可能不兼容,可在创建复制账号时指定mysql_native_password。
六、常见误区与改进
有人以为depends_on能等主库“就绪”,其实它只等容器启动,MySQL进程可能还在初始化。所以必须配合等待脚本或健康检查。另外,把root密码明文写进compose文件有安全风险,生产环境应使用secret管理。
对于更高要求的环境,可把主从部署到Kubernetes,用StatefulSet加Headless Service,配合Operator自动运维。但docker compose方案足以覆盖本地开发、功能测试与教学演示场景,且排错直观。
MySQL主从复制docker_compose修改时间:2026-08-12 01:45:31