不能只靠 docker-compose.yml 文件写两个 mysql:8.0 服务就自动形成主从;必须显式配置 binlog、server-id、复制用户,并在从库启动后动态执行 CHANGE REPLICATION SOURCE TO 和 START REPLICA。

直接说结论:不能只靠 docker-compose.yml 文件写两个 mysql:8.0 服务就自动形成主从。主从关系不是容器自发现的,必须显式配置 binlog、server-id、复制用户,并在从库启动后动态执行 CHANGE REPLICATION SOURCE TO 和 START REPLICA —— 这些 SQL 必须由脚本触发,否则 SHOW REPLICA STATUS 永远显示 Slave_IO_Running: No。
主库配置必须启用 log-bin 且 server-id 唯一
MySQL 8.0 主从依赖二进制日志同步,主库不开启 log-bin,从库连日志都拉不到。常见错误是只改了 server-id 却漏掉 log-bin 或拼错参数名(比如写成 log_bin,实际应为 log-bin)。
-
my.cnf中必须包含:server-id=1、log-bin=mysql-bin、binlog-format=ROW - 推荐加上
gtid-mode=ON和enforce-gtid-consistency=true,避免后续切换时位点错乱 - 不要设
bind-address=127.0.0.1—— 容器内 localhost 不等于其他容器可访问的地址,应留空或设为0.0.0.0 - 挂载配置时,路径要精确:
/opt/mysql/master/my.cnf:/etc/my.cnf(注意不是/etc/mysql/my.cnf,官方镜像读的是前者)
从库必须用 entrypoint.sh 自动完成 CHANGE + START
硬编码 SOURCE_LOG_FILE 和 SOURCE_LOG_POS 在 command 字段里是不可靠的:每次容器重建,主库 binlog 文件名和初始 position 都会变。正确做法是让从库容器启动后,先等主库就绪,再连上去查 SHOW MASTER STATUS,最后拼出正确的 CHANGE REPLICATION SOURCE TO 语句。
- 把初始化逻辑写进
entrypoint.sh,挂载进从库容器(如-v ./entrypoint-slave.sh:/docker-entrypoint-initdb.d/entrypoint.sh) - 脚本里要用
mysql -h mysql-master -u root -prootpass -e "SHOW MASTER STATUS"获取实时位点 - 必须创建复制用户,且授权范围是
'repl'@'%'(不是'repl'@'localhost'),否则从库连不上 - 执行
START REPLICA后建议加mysql -e "SHOW REPLICA STATUS\G" | grep -E "(IO|SQL)_Running:"做简单校验
docker-compose.yml 必须隔离网络、数据卷与配置路径
主从共用一个网络是必须的,但共用数据卷或配置文件会导致冲突。常见翻车点是两个服务都挂载了同一目录下的 my.cnf,结果从库加载了主库的配置,server-id 冲突直接启动失败。
- 定义自定义网络:
networks: mysql-net: driver: bridge,所有服务都加入它 - 主从各用独立数据卷:
volumes: - master-data:/var/lib/mysql和- slave1-data:/var/lib/mysql - 配置文件路径必须分开:
./master/my.cnf:/etc/my.cnf和./slave/my.cnf:/etc/my.cnf - 从库
command不要覆盖整个启动流程;优先用entrypoint,它在mysqld启动前执行,更可控
复杂点在于:主从不是“配完就通”,而是“配完+跑对脚本才通”。最容易被忽略的是复制用户的 host 段写成 'repl'@'mysql-master' —— 容器 DNS 解析的是 IP,而 MySQL 用户权限匹配的是连接时声明的 host 名,必须用 '%' 或明确指定主库容器 IP 段(如 'repl'@'172.20.0.%')。


















