加载中...

文章背景图

手把手搭建MySQL主从复制(Ubuntu Docker主库到飞牛NAS备库)

2026-08-27
8
- 字
- 分钟

最近在折腾宿舍的服务器,想把 Ubuntu 上 Docker 里的 MySQL 主库,同步一份到我的飞牛 NAS 上做个备库。本以为是个常规操作,结果一路踩坑,从中午搞到晚上。这篇文章就把整个过程和所有踩过的坑记录下来,希望对你有帮助。

项目背景

  • 主库:Ubuntu 服务器(IP: 192.168.3.10),MySQL 通过宝塔面板安装(宿主机版,非 Docker)。

  • 备库:飞牛 NAS(IP: 192.168.3.9),MySQL 通过 fnOS 图形化 Docker 界面部署。

  • 目标:实现 MySQL 主从复制,主库数据实时同步到备库。

最终成功的配置方案

一、主库(Ubuntu 宝塔 MySQL)配置

  1. 开启必要功能
    在宝塔面板 -> 软件商店 -> MySQL -> 设置 -> 配置修改,在 [mysqld] 段下加入:

    [mysqld]
    server-id=1
    log-bin=mysql-bin
    binlog_format=ROW
    gtid_mode=ON
    enforce_gtid_consistency=ON


    保存后重启 MySQL。

  2. 创建复制专用账号
    登录主库 phpMyAdmin,执行 SQL:

    CREATE USER 'repl'@'%' IDENTIFIED BY '你的密码';
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
    FLUSH PRIVILEGES;


    ⚠️ 坑点:MySQL 8.0 默认认证插件是 caching_sha2_password,创建用户时不要加 IDENTIFIED WITH mysql_native_password,否则会报错 Plugin 'mysql_native_password' is not loaded。

二、备库(飞牛 NAS Docker MySQL)配置

准备目录和配置文件

/vol2/1000/docker/mysql/
├── conf/
│ └── replica.cnf ← 配置文件
└── data/ ← 数据目录
replica.cnf 内容如下:

[mysqld]
server-id=2
relay-log=relay-bin
log-bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
read_only=ON
super_read_only=ON
⚠️ 坑点:fnOS 图形界面只能挂载目录对目录,不能挂载单个文件。所以要把 replica.cnf 放进 conf/ 目录,然后挂载 conf/ 目录到容器内的 /etc/mysql/conf.d/。MySQL 会自动加载该目录下所有 .cnf 文件。

启动容器

docker run -d \
--name mysql-slave \
--network bridge \
-p 3307:3306 \
-v /vol2/1000/docker/mysql/data:/var/lib/mysql \
-v /vol2/1000/docker/mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=你的密码 \
-e TZ=Asia/Shanghai \
mysql:8.0

数据同步与复制建立(标准流程)

锁定主库并记录位点

FLUSH TABLES WITH READ LOCK;
SHOW BINARY LOG STATUS;
-- 记下 File 和 Position,例如:mysql-bin.000001, 157

导出主库数据(排除 phpMyAdmin 系统表)

mysqldump -u root -p --all-databases --ignore-table=phpmyadmin.表名 > /root/full.sql
⚠️ 坑点:如果不排除 phpMyAdmin 的系统表,导入备库后会导致备库的 phpMyAdmin 配置出错,甚至打不开。

解锁主库

UNLOCK TABLES;

将数据导入备库

# 将 full.sql 传到飞牛 NAS
scp /root/full.sql root@192.168.3.9:/vol2/1000/docker/mysql/
# 导入备库
docker exec -i mysql-slave mysql -uroot -p'密码' < /vol2/1000/docker/mysql/full.sql

在备库建立复制关系(使用新语法)

STOP REPLICA;
RESET REPLICA ALL;

CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.3.10',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='你的密码',
SOURCE_LOG_FILE='mysql-bin.000001',根据主库信息填写
SOURCE_LOG_POS=157;根据主库信息填写

START REPLICA;
SHOW REPLICA STATUS;
⚠️ 坑点:MySQL 8.4 及以上版本,CHANGE MASTER TO、START SLAVE、SHOW SLAVE STATUS 等旧语法已废弃,必须使用 CHANGE REPLICATION SOURCE TO、START REPLICA、SHOW REPLICA STATUS 等新语法。同样,SHOW MASTER STATUS 也要改为 SHOW BINARY LOG STATUS。

踩坑全记录(血泪史)

坑 1:备库 server-id 与主库冲突

  • 现象:备库报错 Fatal error: source and replica have equal MySQL server ids

  • 原因:备库未配置 server-id,默认值为 1,与主库冲突。

  • 解决:在备库的 replica.cnf 中设置 server-id=2。

坑 2:fnOS 挂载配置文件方式错误

  • 现象:容器启动报错 Can't read dir of '/etc/mysql/conf.d/'

  • 原因:在 fnOS 图形界面中将 replica.cnf 文件直接挂载到了容器内的目录路径上,导致容器认为该路径是一个文件而非目录。

  • 解决:挂载 conf/ 目录到 /etc/mysql/conf.d/。

坑 3:导入数据时包含了 phpMyAdmin 系统表

  • 现象:备库的 phpMyAdmin 配置异常,无法正常使用。

  • 原因:全量导出时未排除 phpMyAdmin 的系统表,导入后污染了备库的配置。

  • 解决:导出时使用 --ignore-table=phpmyadmin.表名 排除。

坑 4:导出数据后主库有新写入,导致主键冲突

  • 现象:复制状态报错 Error_code: 1062(主键冲突)。

  • 原因:导出数据后,主库又有新的写入操作,这些操作的 binlog 被备库重放时,与已导入的历史数据发生主键冲突。

  • 解决:导出前锁定主库(FLUSH TABLES WITH READ LOCK),导出完成后记录位点并立即解锁,确保数据一致性。

坑 5:GTID 残留导致复制混乱

  • 现象:SHOW REPLICA STATUS 中 Retrieved_Gtid_Set 出现多个不同的 UUID。

  • 原因:多次尝试建立复制关系导致备库积累了错误的 GTID 信息,与主库的 GTID 集合对不上。

  • 解决:彻底重建备库容器,清空数据目录,重新导入数据和建立复制。

总结

折腾完这一趟,感觉比写一天代码还累。但收获也很大,对 MySQL 主从复制的理解深了不少。总结几点经验:

  1. 版本很重要:MySQL 8.4 语法变化很大,网上很多旧教程已经不适用了,一定要以官方文档为准。

  2. 环境差异要留意:宝塔面板的 MySQL 和纯 Docker 部署的 MySQL 配置路径完全不同,要先搞清楚自己的环境。

  3. 数据一致性是命门:导出数据前一定要锁定主库,记录准确的 binlog 位点,这是避免后续各种奇怪问题的关键。

  4. 备库配置要干净:备库的配置要独立,server-id 不能重复,GTID 状态要干净,最好从重建容器开始。

希望这篇文章能帮你少走弯路。如果你也在折腾类似的架构,欢迎留言交流!

原创

手把手搭建MySQL主从复制(Ubuntu Docker主库到飞牛NAS备库)

本文链接: 手把手搭建MySQL主从复制(Ubuntu Docker主库到飞牛NAS备库)

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

评论交流

文章目录