云服务器部署 MySQL 8.0 一主两从架构(Docker 版):从零搭建数据同步集群
目录
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 主从复制是实现数据高可用、读写分离的经典方案。本文以通用云服务器(如阿里云 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 - 用户名和密码同上
- 连接名:
五、常见问题与解决方案
-
从库 Slave_IO_Running 状态为 Connecting
- 检查主库 IP、端口是否正确,复制用户密码是否错误。
- 验证从库到主库的网络连通性:
docker exec -it slave01 ping 172.20.0.2。 - 重新在主库授权:
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;。
-
远程连接超时(10060 错误)
- 检查云服务器安全组是否开放目标端口。
- 确认服务器防火墙已放行端口。
- 验证容器是否正常运行:
docker ps | grep mysql。
-
数据同步延迟或失败
- 查看从库错误日志:
SHOW SLAVE STATUS\G中的Last_IO_Error和Last_SQL_Error。 - 若因 SQL 错误导致同步中断,可临时跳过错误:
STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE;。
- 查看从库错误日志:
六、总结
本文详细介绍了在云服务器上通过 Docker 部署 MySQL 8.0 一主两从架构的全过程,核心在于正确配置主从库的server-id、二进制日志及复制用户权限。通过该架构,可实现数据实时备份和读写分离,显著提升系统的可用性和性能。
实际生产环境中,还可结合监控工具(如 Prometheus+Grafana)监控主从同步状态,或通过 Keepalived 实现主库故障自动切换,进一步增强集群的稳定性。按照本文步骤操作,即可快速搭建一套可靠的 MySQL 主从复制集群,为业务提供坚实的数据支撑。
更多推荐
所有评论(0)