目录

一、主从复制的核心价值

二、前期准备

1. 环境要求

三、详细部署步骤

第一步:清理环境,确保初始状态干净

第二步:创建基础网络与目录结构

1. 搭建自定义桥接网络

2. 构建目录结构(持久化配置与数据)

第三步:获取 MySQL 8.0 默认配置文件

第四步:修改配置文件(主从核心配置)

1. 主库配置(/root/docker/volumes/etc/master/my.cnf)

2. 从库 1 配置(/root/docker/volumes/etc/slave01/my.cnf)

3. 从库 2 配置(/root/docker/volumes/etc/slave02/my.cnf)

第五步:设置数据目录权限

第六步:启动 MySQL 容器

第七步:获取容器 IP 地址

第八步:配置主从复制(核心环节)

1. 主库创建复制用户并获取 binlog 信息

2. 从库 1(172.20.0.3)配置同步

3. 从库 2(172.20.0.4)配置同步

第九步:验证主从同步功能

1. 主库插入测试数据

2. 从库验证数据同步

四、远程连接云服务器上的 MySQL(以 Navicat 为例)

1. 开放云服务器端口(安全组 / 防火墙)

2. Navicat 连接配置

五、常见问题与解决方案

六、总结


在企业级应用中,MySQL 主从复制是实现数据高可用、读写分离的经典方案。本文以通用云服务器(如阿里云 ECS、腾讯云 CVM、华为云 ECS 等)为例,详细介绍如何通过 Docker 快速部署 MySQL 8.0 一主两从架构,涵盖环境清理、配置优化、主从同步配置及远程连接等全流程,适合运维工程师和开发人员参考实践。

一、主从复制的核心价值

MySQL 主从复制通过二进制日志(binlog)实现主库(Master)与从库(Slave)的数据同步,主要应用场景包括:

  • 数据备份:从库实时同步主库数据,避免单点故障导致数据丢失。
  • 读写分离:主库负责写入操作,从库承担查询请求,提升系统并发能力。
  • 负载均衡:多从库可分散查询压力,优化数据库响应速度。

采用 Docker 部署的优势在于:环境隔离性强、配置复用率高、版本管理便捷,且无需担心操作系统差异带来的兼容性问题。

二、前期准备

1. 环境要求

  • 云服务器实例(推荐配置:2 核 4G 内存,操作系统为 CentOS 7/8、Ubuntu 20.04 或 Debian 11)。
  • 已安装 Docker(可参考Docker部署)。
  • 本地工具:SSH 客户端(如 Xshell、FinalShell)、MySQL 图形化工具(如 Navicat、DBeaver)。

三、详细部署步骤

第一步:清理环境,确保初始状态干净(可自行选择)

为避免旧容器、网络或配置文件干扰,先执行彻底清理:

# 停止并删除相关容器
docker stop master slave01 slave02 2>/dev/null
docker rm master slave01 slave02 2>/dev/null

# 删除自定义网络(若存在)
docker network rm mysql-network 2>/dev/null

# 清理配置文件和数据目录(彻底重置)
rm -rf /root/docker/volumes/etc/{master,slave01,slave02}
rm -rf /root/docker/volumes/var/lib/{master,slave01,slave02}

# 验证清理结果(应无输出)
echo "剩余容器检查:"
docker ps -a | grep -E "master|slave01|slave02"
echo "剩余网络检查:"
docker network ls | grep mysql-network

第二步:创建基础网络与目录结构

1. 搭建自定义桥接网络

为 MySQL 集群创建独立网络,确保主从库之间通信稳定且与其他服务隔离:

docker network create \
  --driver bridge \
  --subnet 172.20.0.0/16 \
  --gateway 172.20.0.1 \
  mysql-network

# 验证网络创建成功
docker network ls | grep mysql-network
2. 构建目录结构(持久化配置与数据)

创建本地目录用于挂载 Docker 容器内的配置文件和数据,实现持久化存储:

# 配置文件目录(主库、从库1、从库2)
mkdir -p /root/docker/volumes/etc/{master,slave01,slave02}/{my.cnf.d,conf.d}
# 数据存储目录
mkdir -p /root/docker/volumes/var/lib/{master,slave01,slave02}

第三步:获取 MySQL 8.0 默认配置文件

从官方镜像导出默认配置,避免手动编写配置文件时出现格式错误:

# 导出主配置文件(my.cnf)
docker run --rm mysql:8.0 cat /etc/my.cnf > /root/docker/volumes/etc/master/my.cnf
docker run --rm mysql:8.0 cat /etc/my.cnf > /root/docker/volumes/etc/slave01/my.cnf
docker run --rm mysql:8.0 cat /etc/my.cnf > /root/docker/volumes/etc/slave02/my.cnf

# 启动临时容器,用于复制扩展配置文件
docker run --rm --name temp-mysql -d \
  --entrypoint /bin/sh mysql:8.0 \
  -c "while true; do sleep 3600; done"

# 复制扩展配置到本地目录
docker cp temp-mysql:/etc/my.cnf.d/. /root/docker/volumes/etc/master/my.cnf.d/
docker cp temp-mysql:/etc/mysql/conf.d/. /root/docker/volumes/etc/master/conf.d/
docker cp temp-mysql:/etc/my.cnf.d/. /root/docker/volumes/etc/slave01/my.cnf.d/
docker cp temp-mysql:/etc/mysql/conf.d/. /root/docker/volumes/etc/slave01/conf.d/
docker cp temp-mysql:/etc/my.cnf.d/. /root/docker/volumes/etc/slave02/my.cnf.d/
docker cp temp-mysql:/etc/mysql/conf.d/. /root/docker/volumes/etc/slave02/conf.d/

# 停止临时容器
docker stop temp-mysql

第四步:修改配置文件(主从核心配置)

MySQL 8.0 的主从复制依赖server-id、二进制日志(binlog)、中继日志(relay-log)等关键配置,同时需兼容认证插件:

1. 主库配置(/root/docker/volumes/etc/master/my.cnf
# 在[mysqld]节点后添加核心配置
sed -i '/\[mysqld\]/a server-id = 1\nlog_bin = /var/lib/mysql/mysql-bin\n#binlog_do_db = test\nbinlog_expire_logs_seconds = 604800\ndefault_authentication_plugin = mysql_native_password' /root/docker/volumes/etc/master/my.cnf

# 验证配置是否生效
grep -A 5 "\[mysqld\]" /root/docker/volumes/etc/master/my.cnf
  • server-id = 1:主库唯一标识(不可与从库重复)。
  • log_bin:启用二进制日志(主从复制的基础)。
  • binlog_do_db = test:仅同步test数据库(可根据业务修改)。
  • default_authentication_plugin:指定默认认证插件为mysql_native_password,解决客户端连接时的认证问题。
2. 从库 1 配置(/root/docker/volumes/etc/slave01/my.cnf
sed -i '/\[mysqld\]/a server-id = 2\nrelay_log = /var/lib/mysql/relay-bin\nread_only = 1\ndefault_authentication_plugin = mysql_native_password' /root/docker/volumes/etc/slave01/my.cnf

# 验证配置
grep -A 4 "\[mysqld\]" /root/docker/volumes/etc/slave01/my.cnf
3. 从库 2 配置(/root/docker/volumes/etc/slave02/my.cnf
sed -i '/\[mysqld\]/a server-id = 3\nrelay_log = /var/lib/mysql/relay-bin\nread_only = 1\ndefault_authentication_plugin = mysql_native_password' /root/docker/volumes/etc/slave02/my.cnf

# 验证配置
grep -A 4 "\[mysqld\]" /root/docker/volumes/etc/slave02/my.cnf
  • 从库server-id分别为 2 和 3(需唯一且与主库不同)。
  • relay_log:从库用于存储主库同步过来的二进制日志。
  • read_only = 1:设置从库为只读模式(增强数据安全性)。

第五步:设置数据目录权限

Docker 容器内的 MySQL 进程默认使用用户 ID 999,需确保本地数据目录权限匹配,避免启动失败:

chown -R 999:999 /root/docker/volumes/var/lib/{master,slave01,slave02}

第六步:启动 MySQL 容器

通过 Docker 命令启动主库和从库,映射端口并挂载配置 / 数据目录:

# 启动主库(映射到云服务器3308端口)
docker run --name master \
  --network mysql-network \
  -p 3308:3306 \
  -v /root/docker/volumes/etc/master/my.cnf:/etc/my.cnf \
  -v /root/docker/volumes/etc/master/my.cnf.d:/etc/my.cnf.d \
  -v /root/docker/volumes/etc/master/conf.d:/etc/mysql/conf.d \
  -v /root/docker/volumes/var/lib/master:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=1234567900 \
  -d mysql:8.0

# 启动从库1(映射到云服务器3309端口)
docker run --name slave01 \
  --network mysql-network \
  -p 3309:3306 \
  -v /root/docker/volumes/etc/slave01/my.cnf:/etc/my.cnf \
  -v /root/docker/volumes/etc/slave01/my.cnf.d:/etc/my.cnf.d \
  -v /root/docker/volumes/etc/slave01/conf.d:/etc/mysql/conf.d \
  -v /root/docker/volumes/var/lib/slave01:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=1234567900 \
  -d mysql:8.0

# 启动从库2(映射到云服务器3310端口)
docker run --name slave02 \
  --network mysql-network \
  -p 3310:3306 \
  -v /root/docker/volumes/etc/slave02/my.cnf:/etc/my.cnf \
  -v /root/docker/volumes/etc/slave02/my.cnf.d:/etc/my.cnf.d \
  -v /root/docker/volumes/etc/slave02/conf.d:/etc/mysql/conf.d \
  -v /root/docker/volumes/var/lib/slave02:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=1234567900 \
  -d mysql:8.0

# 检查容器状态(确保均为Up状态)
docker ps | grep -E "master|slave01|slave02"
  • 若容器启动失败,通过docker logs master查看日志(常见原因:配置文件语法错误、目录权限不足)。

第七步:获取容器 IP 地址

记录主从库在自定义网络中的 IP 地址(用于后续主从同步配置):

# 主库IP
MASTER_IP=$(docker inspect -f '{{index .NetworkSettings.Networks "mysql-network" "IPAddress"}}' master)
echo "主库IP:$MASTER_IP"  # 示例:172.20.0.2

# 从库1IP
echo "从库1IP:$(docker inspect -f '{{index .NetworkSettings.Networks "mysql-network" "IPAddress"}}' slave01)"  # 示例:172.20.0.3

# 从库2IP
echo "从库2IP:$(docker inspect -f '{{index .NetworkSettings.Networks "mysql-network" "IPAddress"}}' slave02)"  # 示例:172.20.0.4

第八步:配置主从复制(核心环节)

1. 主库创建复制用户并获取 binlog 信息
# 进入主库容器
docker exec -it master /bin/bash

# 连接MySQL(密码:1234567900)
mysql -uroot -p

在 MySQL 命令行执行:

-- 创建复制专用用户(允许所有IP连接,实际可限制为从库IP)
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'Repl@123456';

-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

-- 刷新权限
FLUSH PRIVILEGES;

-- 确认用户配置(plugin字段应为mysql_native_password)
SELECT user, host, plugin FROM mysql.user WHERE user = 'repl';

-- 刷新二进制日志(生成新的日志文件)
FLUSH BINARY LOGS;

-- 查看当前binlog信息(记录File和Position)
SHOW MASTER STATUS;

关键输出(需记录):

示例:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 | test         |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
  • File:二进制日志文件名(如mysql-bin.000001)。
  • Position:日志位置(如 154),从库将从此位置开始同步数据。
2. 从库 1(172.20.0.3)配置同步
# 进入从库1容器
docker exec -it slave01 /bin/bash

# 连接MySQL(密码:1234567900)
mysql -uroot -p1234567900

在 MySQL 命令行执行:

-- 重置复制配置(清除旧配置)
RESET SLAVE ALL;

-- 配置主库信息(替换为实际参数)
CHANGE MASTER TO
  MASTER_HOST = '172.20.0.2',  -- 主库IP
  MASTER_PORT = 3306,
  MASTER_USER = 'repl',
  MASTER_PASSWORD = 'Repl@123456',
  MASTER_LOG_FILE = 'mysql-bin.000001',  -- 主库binlog文件名
  MASTER_LOG_POS = 154;  -- 主库binlog位置

-- 启动从库复制进程
START SLAVE;

-- 查看复制状态(核心:Slave_IO_Running和Slave_SQL_Running需为Yes)
SHOW SLAVE STATUS\G
3. 从库 2(172.20.0.4)配置同步

操作与从库 1 完全一致,使用相同的主库 IP、复制用户密码及 binlog 信息。

# 进入从库2容器
docker exec -it slave02 /bin/bash

# 连接MySQL(密码:1234567900)
mysql -uroot -p1234567900

第九步:验证主从同步功能

1. 主库插入测试数据

在系统命令行执行以下代码

# 在主库创建测试数据(使用英文避免引号转义问题)
docker exec -it master /bin/bash -c '
  mysql -uroot -p1234567900 -e "
    CREATE DATABASE IF NOT EXISTS test;
    USE test;
    CREATE TABLE IF NOT EXISTS sync_check (
      id INT PRIMARY KEY AUTO_INCREMENT,
      info VARCHAR(100) NOT NULL,
      create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    INSERT INTO sync_check (info) VALUES (\"master-slave-sync-test\");
  "
'
2. 从库验证数据同步
# 从库1查询数据
docker exec -it slave01 mysql -uroot -p1234567900 -e "USE test; SELECT * FROM sync_check;"

# 从库2查询数据
docker exec -it slave02 mysql -uroot -p1234567900 -e "USE test; SELECT * FROM sync_check;"

若从库查询到master-slave-sync-test记录,说明主从同步配置成功。

四、远程连接云服务器上的 MySQL(以 Navicat 为例)

1. 开放云服务器端口(安全组 / 防火墙)

  • 安全组配置:登录云服务商控制台,在实例安全组中开放 3308、3309、3310 端口(授权对象可限制为本地 IP)。
  • 服务器防火墙
    # 开放端口(CentOS示例)
    firewall-cmd --zone=public --add-port=3308/tcp --permanent
    firewall-cmd --zone=public --add-port=3309/tcp --permanent
    firewall-cmd --zone=public --add-port=3310/tcp --permanent
    firewall-cmd --reload
    

2. Navicat 连接配置

  • 主库连接

    • 连接名:MySQL-Master
    • 主机:云服务器公网 IP(如123.xxx.xxx.xxx
    • 端口:3308
    • 用户名:root
    • 密码:1234567900
  • 从库 1 连接

    • 连接名:MySQL-Slave01
    • 主机:云服务器公网 IP
    • 端口:3309
    • 用户名和密码同上
  • 从库 2 连接

    • 连接名:MySQL-Slave02
    • 主机:云服务器公网 IP
    • 端口:3310
    • 用户名和密码同上

五、常见问题与解决方案

  1. 从库 Slave_IO_Running 状态为 Connecting

    • 检查主库 IP、端口是否正确,复制用户密码是否错误。
    • 验证从库到主库的网络连通性:docker exec -it slave01 ping 172.20.0.2
    • 重新在主库授权:GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;
  2. 远程连接超时(10060 错误)

    • 检查云服务器安全组是否开放目标端口。
    • 确认服务器防火墙已放行端口。
    • 验证容器是否正常运行:docker ps | grep mysql
  3. 数据同步延迟或失败

    • 查看从库错误日志:SHOW SLAVE STATUS\G中的Last_IO_ErrorLast_SQL_Error
    • 若因 SQL 错误导致同步中断,可临时跳过错误:STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE;

六、总结

本文详细介绍了在云服务器上通过 Docker 部署 MySQL 8.0 一主两从架构的全过程,核心在于正确配置主从库的server-id、二进制日志及复制用户权限。通过该架构,可实现数据实时备份和读写分离,显著提升系统的可用性和性能。

实际生产环境中,还可结合监控工具(如 Prometheus+Grafana)监控主从同步状态,或通过 Keepalived 实现主库故障自动切换,进一步增强集群的稳定性。按照本文步骤操作,即可快速搭建一套可靠的 MySQL 主从复制集群,为业务提供坚实的数据支撑。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐