> 技术文档 > Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

Docker镜像制作的命令 链接

Docker 镜像制作的注意事项 链接

搭建mysql主从集群

mysql主从同步的原理

MySQL主从同步(Replication)是一种实现数据冗余和高可用性的技术,通过将主数据库(Master)的变更操作同步到一个或多个从数据库(Slave),实现数据的实时或准实时复制

为什么要用主从分离?

  • 读写分离,提高性能:主库负责写,从库负责读

  • 数据实时备份:主库的数据实时存储到从库

  • 高可用HA:当有一个节点发生故障时,可以随时切换

核心流程

主库记录变更日志(Binary Log)

  • 主库将所有数据变更操作(如INSERT、UPDATE、DELETE)记录到二进制日志(Binary Log)中。
  • Binary Log是二进制格式的文件,记录了每个事务的SQL语句或行级变更。

从库读取主库的日志

  • 从库通过I/O线程连接到主库,并请求读取Binary Log。
  • 主库的I/O线程将Binary Log的内容发送给从库。

从库重放日志(Relay Log)

  • 从库将接收到的Binary Log写入本地的中继日志(Relay Log)。
  • 从库的SQL线程读取Relay Log,并按照顺序执行其中的SQL语句,从而实现数据同步。

数据一致性保障

  • 主库和从库通过日志的顺序执行保证数据一致性。
  • 异步复制模式下,从库可能稍有延迟;半同步复制模式下,主库会等待至少一个从库确认接收日志。

主从分布架构图

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

组件 作用 Binary Log 主库记录所有数据变更的日志,是主从同步的核心。 I/O线程 从库的线程,负责从主库获取Binary Log并写入Relay Log。 SQL线程 从库的线程,负责读取Relay Log并执行其中的SQL语句。 Relay Log 从库本地存储主库Binary Log的中间日志,用于SQL线程重放。

当主节点mysql接收到数据的时候,向binlog写入事务,binlog通过多线程的读取,发送到从节点,从节点先由IO线程接收,然后再写入laylog中,之后让laolog线程进行读取,最后放入到从节点的mysql中

主从同步的方式

异步复制(Asynchronous Replication)

主库提交事务后立即返回,不等待从库确认。

  • 优点:性能高,延迟低。
  • 缺点:从库可能滞后,数据一致性较差。
    Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

半同步复制(Semi-Synchronous Replication)

主库提交事务后,至少等待一个从库确认接收日志

  • 优点:数据一致性更好。
  • 缺点:性能略有下降。
    Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

全同步复制(Synchronous Replication)

主库提交事务后,等待所有从库确认接收日志

  • 优点:数据一致性更好。
  • 缺点:性能较低。
    Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

增强半同步复制 (Rising-Semi-Synchronous Replication)

对半同步复制做的一个改进,原理上几乎是一样的,主要是解决幻读的问题.

  • 优点:数据一致性更好,解决幻读问题
  • 缺点:性能略有下降
    Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

主要配置

1.主库配置
启用Binary Log:

[mysqld]log-bin=mysql-binserver-id=1 # 唯一标识符

创建同步用户(供从库连接):

CREATE USER \'repl\'@\'%\' IDENTIFIED BY \'password\';GRANT REPLICATION SLAVE ON *.* TO \'repl\'@\'%\';

2.从库配置
指定主库信息:

CHANGE MASTER TO MASTER_HOST=\'master_host\', MASTER_USER=\'repl\', MASTER_PASSWORD=\'password\', MASTER_LOG_FILE=\'mysql-bin.000001\', MASTER_LOG_POS=120;

启动同步:

START SLAVE;

3.验证同步状态
检查从库状态:

SHOW SLAVE STATUS\\G;

实战

创建对应目录
Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file

编辑Master目录下的Dockerfile:

FROM mysql:5.7.36RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 

FROM mysql:5.7.36:这一行指定了 Docker 镜像的基础镜像。
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime:

  • RUN 是 Dockerfile 中的一个指令,表示在构建镜像时运行指定的命令。
  • ln -sf 是创建符号链接(symbolic link)的命令:
  • -s 表示创建符号链接(软链接)。
  • -f 表示如果目标文件已存在,则强制覆盖。
  • /usr/share/zoneinfo/Asia/Shanghai 是系统中的时区文件,表示中国上海时区(东八区)。
  • /etc/localtime 是 Linux 系统中表示当前容器时区的文件。
    这一行的作用是将 /etc/localtime 链接到 /usr/share/zoneinfo/Asia/Shanghai,从而将容器的时区设置为上海时区(UTC+8)。

编辑slave目录下的Dockerfile:

FROM mysql:5.7.36RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtimeCOPY ./slave/slave.sql /docker-entrypoint-initdb.d

编辑slave.sql

change master to master_host=\'mysql-master\', master_user=\'root\',master_password=\'root\',master_port=3306;start slave;

CHANGE MASTER TO 语句:用于配置从库连接主库的相关信息。
参数说明:

  • master_host=‘mysql-master’:
    指定主库的主机名或 IP 地址,这里的主库名是 mysql-master。
  • master_user=‘root’:
    指定用于从库连接主库的用户名,这里是 root。
  • master_password=‘root’:
    指定用于从库连接主库的密码,这里是 root。
  • master_port=3306:
    指定主库的端口号,这里是默认的 MySQL 端口 3306。
  • 作用:
    这部分语句告诉从库如何连接到主库,包括主库地址、用户名、密码和端口号

START SLAVE 语句:

  • 用于启动从库的复制进程。
  • 在执行 CHANGE MASTER TO 配置后,从库需要执行 START SLAVE; 才能开始从主库拉取数据并同步

在主目录mysqlcluster下创建docker-compose.yml文件进行编辑:

name: mysqlclusterservices: mysql-master: build: context: ./ dockerfile: ./master/Dockerfile image: mysqlmaster:1.0 restart: always container_name: mysql-master volumes: - ./mastervarlib:/var/lib/mysql ports: - 8080:3306 environment: MYSQL_ROOT_PASSWORD: root privileged: true command: [\'--server-id=1\', \'--log-bin=master-bin\', \'--binlog-ignore-db=mysql\', \'--binlog_cache_size=256M\', \'--binlog_format=mixed\', \'--lower_case_table_names=1\', \'--character-set-server=utf8\', \'--collation-server=utf8_general_ci\'] mysql-slave: build: context: ./ dockerfile: ./slave/Dockerfile image: mysqlslave:1.0 restart: always container_name: mysql-slave volumes: - ./slavevarlib:/var/lib/mysql ports: - 8081:3306 environment: MYSQL_ROOT_PASSWORD: root privileged: true command: [\'--server-id=2\', \'--relay_log=slave-relay\', \'--lower_case_table_names=1\', \'--character-set-server=utf8\', \'--collation-server=utf8_general_ci\'] depends_on: - mysql-master mysql-slave2: build: context: ./ dockerfile: ./slave/Dockerfile image: mysqlslave:1.0 restart: always container_name: mysql-slave2 volumes: - ./slavevarlib2:/var/lib/mysql ports: - 8082:3306 environment: MYSQL_ROOT_PASSWORD: root privileged: true command: [\'--server-id=3\', \'--relay_log=slave-relay\', \'--lower_case_table_names=1\', \'--character-set-server=utf8\', \'--collation-server=utf8_general_ci\'] depends_on: - mysql-master

mysql-master:

  • restart:指定容器的重启策略。
    always 表示无论容器因何种原因退出,Docker 都会尝试重新启动它。

  • volume:用于将主机目录挂载到容器中
    ./mastervarlib 是主机上的目录,/var/lib/mysql 是容器中 MySQL 默认的数据存储路径。
    作用:将 MySQL 的数据存储在主机上,确保容器重启或删除后数据不会丢失。

  • envirnment:设置环境变量
    MYSQL_ROOT_PASSWORD: root 指定 MySQL 的 root 用户密码为 root。
    privileged:设置容器以特权模式运行

  • command:
    设置 MySQL 服务器的唯一 ID,主从复制中必须指定,且每个服务器的 ID 必须唯一
    启用二进制日志(Binary Log),日志文件前缀为 master-bin,记录主库的写操作
    指定忽略mysql系统数据库的二进制日志记录
    设置二进制日志缓存的大小为 256MB
    设置二进制日志的格式为 mixed
    设置表名不区分大小写
    设置服务器的默认字符集为 utf8
    设置服务器的默认排序规则为 utf8_general_ci

mysql-slave1:

  • depends-on:指定服务之间的依赖关系
    mysql-slave 服务依赖于 mysql-master 服务
    确保在启动 mysql-slave 之前,mysql-master 服务已经启动

创建出镜像并创建启动对应的容器:

docker compose builddocker compose up -d

查看对应状态

docker ps

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
运行主数据库查看运转

docker exec -it mysql-master bash

连上主库,查看数据库可以看到运行正常

mysql -u root -p

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
连接上从库,通过命令查看

SHOW MASTER STATUS\\GSHOW SLAVE STATUS\\G

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
主库创建一个数据库

create database test;

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
从库上查看,可以看到也有了对应的test数据库:
Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
主库上创建表,插入数据:

mysql> use test;Database changedmysql> create table users(sno int,sname varchar(20));Query OK, 0 rows affected (0.03 sec)mysql> insert into users values (1,\'xixi\');Query OK, 1 row affected (0.02 sec)mysql> insert into users values (2,\'haha\');Query OK, 1 row affected (0.01 sec)

在从表上查看

mysql> use test;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -ADatabase changedmysql> show tables;+----------------+| Tables_in_test |+----------------+| users |+----------------+1 row in set (0.00 sec)mysql> select * from users;+------+-------+| sno | sname |+------+-------+| 1 | xixi || 2 | haha |+------+-------+2 rows in set (0.00 sec)

至此完成了mysql主从集群的部署;

docker compose down

搭建Redis集群

Redis 集群是 Redis 提供的一种分布式解决方案,旨在通过将数据分布到多个节点上来实现水平扩展和高可用性。它解决了单机 Redis 在存储容量、读写性能和容错能力上的限制,适用于大规模、高并发的应用场景。

核心特性

数据分片(Sharding)

  • Redis 集群将数据分散到多个节点上,每个节点负责一部分数据。
  • 数据分片基于哈希槽(Hash Slot),共有 16384 个哈希槽,每个键通过哈希算法映射到一个哈希槽,再分配到具体节点。

高可用性

  • 每个主节点(Master)可以有多个从节点(Slave)。
  • 当主节点故障时,集群会自动将从节点提升为主节点(故障转移),确保服务可用。

水平扩展

  • 可以通过增加节点来扩展集群的存储容量和性能。
  • 集群支持动态添加或移除节点,无需停机。

无中心架构

  • Redis 集群没有中心节点,所有节点平等,避免了单点故障。

下载源码压缩包

首先,我们要去官网,找到源码的下载链接
redis-7.0.15 版本的链接

组成

  • 主节点(Master):负责处理读写请求和存储数据。
  • 从节点(Slave):复制主节点的数据,用于故障转移和只读请求。
  • 哈希槽(Hash Slot):数据分片的基本单位,共有 16384 个。

准备目录

 mkdir /data/ahri/dockerfile/rediscluster/redis

设置redis.conf

在redis目录下创建一个redis.conf进行配置

#表示前台运行daemonize no#端口port 6379#持久化dir /data/redis#启用集群cluster-enabled yes#集群参数配置cluster-config-file nodes.conf#集群超时时间cluster-node-timeout 5000#密码配置requirepass 123456#主节点密码配置masterauth 123456#表示远端可以连接bind * -::*

编辑 Dockefile

在redis目录下创建Dockerfile文件进行编辑

注:centos:7 已经停止维护了,所以这里使用了ubuntu

# 第一阶段:构建阶段FROM ubuntu:22.04 AS buildstage# 更新包列表并安装必要的构建工具和依赖RUN apt-get update && apt-get install -y \\ build-essential \\ wget \\ gcc \\ g++ \\ make \\ && rm -rf /var/lib/apt/lists/*# 下载 Redis 源码和配置文件#wget https://download.redis.io/releases/redis-7.0.15.tar.gzADD redis-7.0.15.tar.gz /ADD redis.conf /redis/# 切换到 Redis 源码目录并编译WORKDIR /redis-7.0.15RUN make # 将 Redis 可执行文件移动到指定目录RUN mv /redis-7.0.15/src/redis-server /redis/ && mv /redis-7.0.15/src/redis-cli /redis/ENTRYPOINT [\"/redis/redis-server\", \"/redis/redis.conf\"]# 第二阶段:运行阶段FROM ubuntu:22.04RUN mkdir -p /data/redis && mkdir -p /redisCOPY --from=buildstage /redis /redisEXPOSE 6379ENTRYPOINT [\"/redis/redis-server\", \"/redis/redis.conf\"] 

测试

通过docker build创建镜像进行测试

docker build -t myredis:v1.0 .

尝试启动一个容器进行测试

docker run -d --name myredis --rm myredis:1.0 416541b280d91f04e80c7df864ed097d5471b26bf93a5c82b090d458402217f9

Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
测试成功,释放资源

docker stop myredis

编写Docker-compose.yml

name: redisclusterservices: redis01: image: myredis:1.0 build: ./redis ports: - 6379:6379 container_name: redis01 healthcheck: test: /redis/redis-cli ping interval: 10s timeout: 5s retries: 10 redis02: image: myredis:1.0 container_name: redis02 healthcheck: test: /redis/redis-cli ping interval: 10s timeout: 5s retries: 10 redis03: image: myredis:1.0 container_name: redis03 healthcheck: test: /redis/redis-cli ping interval: 10s timeout: 5s retries: 10 redis04: image: myredis:1.0 container_name: redis04 healthcheck: test: /redis/redis-cli ping interval: 10s timeout: 5s retries: 10 redis05: image: myredis:1.0 container_name: redis05 healthcheck: test: /redis/redis-cli ping interval: 10s timeout: 5s retries: 10 redis06: image: myredis:1.0 container_name: redis06 healthcheck: test: /redis/redis-cli ping interval: 10s timeout: 5s retries: 10 redis07: image: myredis:1.0 container_name: redis07 entrypoint: [\"/redis/redis-cli\", \"--cluster\", \"create\", \"redis01:6379\", \"redis02:6379\", \"redis03:6379\", \"redis04:6379\", \"redis05:6379\", \"redis06:6379\", \"--cluster-replicas\", \"1\", \"-a\", \"123456\", \"--cluster-yes\"] depends_on: redis01: condition: service_healthy redis02: condition: service_healthy redis03: condition: service_healthy redis04: condition: service_healthy redis05: condition: service_healthy redis06: condition: service_healthy 

测试

通过下面命令检查配置文件是否书写格式错误

docker compose config

对 容器进行启动

docker compose up -d

查看容器的状态
Docker--利用dockerfile搭建mysql主从集群和redis集群_mysql集群部署docker file
查看07日志是否创建成功

root@VM-8-12-ubuntu:/data/ahri/dockerfile/rediscluster# docker logs -f redis07Warning: Using a password with \'-a\' or \'-u\' option on the command line interface may not be safe.>>> Performing hash slots allocation on 6 nodes...Master[0] -> Slots 0 - 5460Master[1] -> Slots 5461 - 10922Master[2] -> Slots 10923 - 16383Adding replica redis05:6379 to redis01:6379Adding replica redis06:6379 to redis02:6379Adding replica redis04:6379 to redis03:6379M: 148bf218eac4b30786ef89e5c5cc1bf4facdf4be redis01:6379 slots:[0-5460] (5461 slots) masterM: 5964d6968e8527be920f1d60aad8e549ac1c327a redis02:6379 slots:[5461-10922] (5462 slots) masterM: 4a33cf88ed2334e78fe468c35446a2a8bd14f805 redis03:6379 slots:[10923-16383] (5461 slots) masterS: 4ee8406f204b7ee8778a40f7d6ec979cc4f9bfff redis04:6379 replicates 4a33cf88ed2334e78fe468c35446a2a8bd14f805S: fb59eccda63bd4bb8d33526262612e1ab694da02 redis05:6379 replicates 148bf218eac4b30786ef89e5c5cc1bf4facdf4beS: 8b7b54ee2f4c7a327e1e954db379a519aa7e68b8 redis06:6379 replicates 5964d6968e8527be920f1d60aad8e549ac1c327a>>> Nodes configuration updated>>> Assign a different config epoch to each node>>> Sending CLUSTER MEET messages to join the clusterWaiting for the cluster to join.>>> Performing Cluster Check (using node redis01:6379)M: 148bf218eac4b30786ef89e5c5cc1bf4facdf4be redis01:6379 slots:[0-5460] (5461 slots) master 1 additional replica(s)M: 4a33cf88ed2334e78fe468c35446a2a8bd14f805 172.19.0.5:6379 slots:[10923-16383] (5461 slots) master 1 additional replica(s)S: 4ee8406f204b7ee8778a40f7d6ec979cc4f9bfff 172.19.0.2:6379 slots: (0 slots) slave replicates 4a33cf88ed2334e78fe468c35446a2a8bd14f805S: fb59eccda63bd4bb8d33526262612e1ab694da02 172.19.0.7:6379 slots: (0 slots) slave replicates 148bf218eac4b30786ef89e5c5cc1bf4facdf4beS: 8b7b54ee2f4c7a327e1e954db379a519aa7e68b8 172.19.0.4:6379 slots: (0 slots) slave replicates 5964d6968e8527be920f1d60aad8e549ac1c327aM: 5964d6968e8527be920f1d60aad8e549ac1c327a 172.19.0.6:6379 slots:[5461-10922] (5462 slots) master 1 additional replica(s)[OK] All nodes agree about slots configuration.>>> Check for open slots...>>> Check slots coverage...[OK] All 16384 slots covered.

登录容器01-06任意一个进行查看
登录进redis客户端

docker exec -it redis02 bash/redis/redis-cli -c -a 123456

查看对应的配置信息

cluster info

查看对应日志

cluster nodes

设置一个key值,然后获取

set a 123get a\"123\"

退出后释放资源

exitexitdocker compose down

注意
[ERR] Node redis01:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
出现这个错误时,检查你的 docker-compose.yml 文件或 Docker 命令,确保每个 Redis 实例的端口映射是唯一的,并且没有冲突