docker-compose.yml仅启动容器,主从复制需配置(server-id、binlog)、网络(自定义bridge、禁bind-address)、初始化脚本(动态获取binlog位点、创建mysql_native_password用户、设置read_only)协同实现。

docker-compose.yml 本身不能“一键”完成主从复制,它只负责拉起容器;真正让主从跑起来的,是配置、网络、初始化脚本三者配合的结果。光写两个 mysql service,不干预启动流程,99% 的情况会卡在 Slave_IO_Running: No。
主库必须显式启用 binlog 且 server-id 唯一
MySQL 容器默认关闭 log-bin,server-id 也不生效——环境变量如 MYSQL_SERVER_ID 只影响初始化,不改运行时配置。
正确做法是用 command 参数传参,或挂载自定义配置文件(推荐前者,避免路径/权限问题):
- 主库
command必须含:--server-id=1 --log-bin=mysql-bin --binlog-format=ROW - 不要写
bind-address=127.0.0.1,否则从库连不上;让 mysqld 监听0.0.0.0:3306 - 若挂载
my.cnf,确保路径为/etc/mysql/conf.d/my.cnf或/etc/mysql/my.cnf,权限644
从库启动前必须动态获取主库 binlog 位点
硬编码 SOURCE_LOG_FILE 和 SOURCE_LOG_POS(比如写死成 mysql-bin.000001 和 157)不可靠:主库重启后位点会变,从库直接报错 Could not find first log file name in binary log index file。
必须让从库容器启动后,先连主库执行 SHOW MASTER STATUS,再拼出 CHANGE REPLICATION SOURCE TO 语句:
- 用
entrypoint.sh而非command实现该逻辑,更可控(command不适合多步判断) - 脚本里加等待逻辑,例如
until mysql -h mysql-master -uroot -prootpass -e "SELECT 1" &> /dev/null; do sleep 2; done - 执行
CHANGE前,确认主库已创建repl用户,且授权范围是'repl'@'%',密码插件用mysql_native_password
网络与认证插件是两个高频失败点
从库连不上主库,错误提示 Can't connect to MySQL server on 'mysql-master' (115),大概率是网络没通或 bind-address 错了。
MySQL 8.0 默认用 caching_sha2_password 插件,但复制线程不支持——导致 IO_Running: No,日志里有 Plugin caching_sha2_password could not be loaded。
- 所有服务必须共用一个自定义 Docker 网络(如
networks: [- mysql-net]),不能依赖默认bridge - 主库创建复制用户时,显式指定插件:
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'replpass'; - 从库的
CHANGE语句中SOURCE_USER/SOURCE_PASSWORD必须和这个一致
从库 read_only=ON 是安全底线
虽然不是启动复制的必要条件,但漏掉会导致从库被误写,后续主从数据不一致,且无法自动修复。
read_only=ON 应写在从库的配置文件或 command 中(如 --read-only),注意它不影响 SUPER 权限用户,所以仍需限制应用账号权限。
另外,MySQL 8.0.31+ 支持 replica_parallel_workers > 0,但在 Docker 网络延迟不稳定时容易触发 Retrieval failed,建议初期保持默认 0。
最易被忽略的是:每次 docker-compose down -v 后,volume 数据保留,但主库的 binlog 文件和 position 已重置;下次 up 时,从库若还按旧位点去拉,必然失败——必须重跑初始化逻辑或清空从库数据卷。


















