一、Operator介绍与使用场景¶
1.1 什么是Operator¶
Operator是一种用于扩展Kubernetes API的自定义控制器,可以实现在原生的资源对象上进行自定义资源类型。通过Operator也可以将复杂的任务转化为对Kubernetes资源的操作,让应用程序的管理和维护更加简单和规范。
1.2 Operator使用场景¶
Operator使用场景如下:
- 简化复杂应用的管理:像管理K8s资源一样管理复杂的系统
- 一致性操作:通过资源定义决定行为,各个环境可以统一配置
- 扩展集群能力:自定义资源类型,扩展集群的调度能力
二、Operator系统组成¶
Operator系统组成分为两部分:
- CRD:Custom Resource Definitions,OperatorKubernetes的CRD来定义新的资源类型,新的类型可像核心资源被管理,比如定义一个叫做Database的CRD,可以用于一键启动一个数据库实例。
- Controller:Operator控制器,该控制器监视自定义资源的状态,并根据用户的配置自动执行相应的操作,比如创建一个数据库,执行一次备份任务等。
三、Operator和Helm对比¶
在Kubernetes中,可以使用Kubernetes的包管理工具非常方便地搭建一个中间件集群,最为常用的包管理工具还是以Operator和Helm为主。
Helm特点如下:
- 更倾向于无状态应用的部署,比如公司的服务、某些不需要持久化数据的中间件、不需要实现额外功能的服务, 比如备份、回滚等
- 使用简单,不需要自己编写代码
Operator特点如下:
- 管理更为复杂的有状态服务,比如MySQL集群、 Redis集群、Rook等。
- 可以利用Operator实现扩容、备份、 回滚等功能
- 相对helm使用复杂,需要有一定的代码能力
四、Operator使用步骤和工作流程¶

使用Helm管理中间件集群的流程如下:
1.集群中需要有一个Helm的客户端,用来执行增删改查命令,和Kubectl类似
2.需要找到对应的Chart(可以在中间件的官网或者GitHub中查找),比如安装Redis、Zookeeper集群的包。这个包和镜像类似,都是放在一个仓库中,镜像放在镜像仓库,Chart放在Chart仓库。
3.新建集群,只需要执行helm install命令即可一键式创建该集群;更新配置,直接使用helm upgrade即可。
使用Operator管理中间件集群的流程如下:
1.找到对应的Operator(可以在GitHub或者其官方网站上查找)
2.创建对应的控制器,用来解析一些自定义资源逻辑的程序
3.创建自定义资源即可,对应的控制器会解析自定义资源实现相关功能,比如创建集群、扩容、备份等
说明:相对于Helm需要安装单独的客户端工具,Operator不需要单独的客户端工具,使用kubectl即可
五、使用一键安装Redis Cluster¶
5.1 Redis Cluster介绍¶
5.1.1 Redis Cluster简单介绍¶
Redis Cluster是Reds的分布式部署模式,可以让多个Redis实例以集群的方式运行,从而提供高可用性、水平扩展和数据冗余的能力。Redis Cluster通过分片(Sharding)和复制(Replication)技术,确保数据可以在多个节点之间分布,并且在节点故障时能够自动恢复。
推荐Operator:https://operatorhub.io/operator/redis-operator
仓库地址:https://github.com/OT-CONTAINER-KIT/redis-operator
国内仓库:https://gitee.com/jeckjohn/redis-operator
官方文档:https://ot-redis-operator.netlify.app/docs/
5.1.2 Redis Cluster集群架构¶

一、数据分片机制:哈希槽(Hash Slot)
- 哈希槽总数 Redis Cluster 将数据划分为 16384 个哈希槽,每个键通过 CRC16 算法计算哈希值,再对 16384 取模得到对应的槽位。
- 槽分配规则
- 每个主节点(Master)负责一部分槽位,例如:
- 节点 A 负责槽 0-5460
- 节点 B 负责槽 5461-10922
- 节点 C 负责槽 10923-16383
- 槽分配信息通过
CLUSTER ADDSLOTS命令手动或自动完成。 - 动态重分片 支持在线迁移槽位,允许集群动态扩展或缩容。例如,添加新节点后,可重新分配槽位以实现负载均衡。
二、节点角色与职责
- 主节点(Master)
- 处理读写请求,负责其分配的哈希槽。
- 参与集群状态投票(如故障检测、新主节点选举)。
- 从节点(Slave)
- 复制主节点的数据,提供数据冗余。
- 在主节点故障时,通过选举机制升级为新的主节点(自动故障转移)。
- 最小集群规模
- 至少需要 3 个主节点 和 3 个从节点(共 6 节点)以实现高可用。
三、节点通信:Gossip 协议
- 通信机制
- 节点间通过 Gossip 协议 定期交换信息(如节点状态、槽位分布)。
- 消息类型包括
PING(检测存活)、PONG(响应)、FAIL(节点下线通知)等。 - 故障检测
- 若某节点在
cluster-node-timeout(默认 15 秒)内未响应,其他节点将其标记为 疑似下线(PFail)。 - 超过半数主节点确认该节点下线后,标记为 已下线(Fail),触发故障转移。
四、客户端交互与重定向
-
智能客户端
-
客户端首次连接集群时,获取槽位分布信息并缓存。
-
直接向目标节点发送请求,减少重定向次数。
-
重定向机制
-
MOVED 错误:键所属槽位已迁移到其他节点,客户端更新缓存并重试。
plaintext
复制
MOVED 1234 192.168.1.2:6379 -
ASK 错误:键所属槽位正在迁移中,客户端临时重定向到目标节点。
plaintext
复制
ASK 1234 192.168.1.3:6379
五、故障转移与恢复
- 自动故障转移
- 当主节点下线时,其从节点发起选举(基于 Raft 算法)。
- 获得多数主节点投票的从节点升级为新主节点。
- 手动干预场景
- 网络分区恢复:需人工介入确认节点状态。
- 部分主节点永久故障:强制触发故障转移(
CLUSTER FAILOVER)。
六、集群管理命令
| 命令 | 用途 |
|---|---|
CLUSTER MEET <ip> <port> |
将新节点加入集群 |
CLUSTER ADDSLOTS <slot> |
分配槽位给当前节点 |
CLUSTER REPLICATE <node-id> |
将当前节点设置为某主节点的从节点 |
CLUSTER INFO |
查看集群状态摘要 |
CLUSTER NODES |
列出集群所有节点信息 |
七、架构优势与限制
- 优势
- 横向扩展:支持动态增加节点提升性能。
- 高可用性:自动故障转移确保服务连续性。
- 去中心化:无单点依赖,节点对等通信。
- 限制
- 不支持跨槽事务:涉及多个槽的
MULTI操作无法保证原子性。 - 批量操作限制:如
MSET需确保所有键在同一槽。 - 迁移复杂性:槽位迁移期间需处理
ASK重定向。
八、典型部署示例
集群节点(6 节点):
- Master1(槽 0-5460) + Slave1
- Master2(槽 5461-10922) + Slave2
- Master3(槽 10923-16383) + Slave3
九、适用场景
- 需要高吞吐、低延迟的分布式缓存。
- 数据量超出单机内存容量,需横向扩展。
- 对高可用性有严格要求的在线服务。
5.2 安装Operator和CRD¶
1、查看集群本身是否安装redis相关的crd,观察到集群本身没有安装CRD
# 返回给空,则代表没有安装
[root@k8s-master01 ~]# kg crd | grep -i rediscluster
[root@k8s-master01 ~]# kubectl api-resources | grep -i rediscluster
2、添加Operator的Helm仓库
[root@k8s-master01 ~]# helm repo add ot-helm https://ot-container-kit.github.io/helm-charts/
3、安装Operator和CRD
[root@k8s-master01 ~]# helm install redis-operator ot-helm/redis-operator --namespace ot-operators --create-namespace
如果镜像拉取不下来,可采用如下命令进行安装
[root@k8s-master01 ~]# helm upgrade --install redis-operator ot-helm/redis-operator --namespace ot-operators --create-namespace --set image.registry=registry.cn-hangzhou.aliyuncs.com --set image.repository=github_images1024/redis-operator --set image.tag=v0.19.1 --set image.pullPolicy=IfNotPresent
4、查看创建的CRD
[root@k8s-master01 ~]# kg crd | grep redis
redis.redis.redis.opstreelabs.in 2025-03-28T00:17:33Z
redisclusters.redis.redis.opstreelabs.in 2025-03-28T00:17:33Z
redisreplications.redis.redis.opstreelabs.in 2025-03-28T00:17:33Z
redissentinels.redis.redis.opstreelabs.in 2025-03-28T00:17:34Z
5、查看生成的pod
[root@k8s-master01 ~]# kgp -n ot-operators
NAME READY STATUS RESTARTS AGE
redis-operator-74f758bc5d-c6rj4 1/1 Running 0 10m
5.3 安装Redis集群¶
参考链接:https://ot-redis-operator.netlify.app/docs/getting-started/cluster/
5.3.1 环境准备¶
5.3.1.1 搭建NFS¶
1、在10.0.0.22主机上搭建NFS
[root@k8s-node02 ~]# yum install nfs-utils rpcbind -y
如果是Ubuntu 系列,则采用下面命令
[root@k8s-node02 ~]# apt install nfs-kernel-server -y
2、配置共享目录
[root@k8s-node02 ~]# mkdir /data/nfs -p
[root@k8s-node02 ~]# chmod -R 775 /data/nfs
[root@k8s-node02 ~]# chown -R :1000 /data/nfs
[root@k8s-node02 ~]# echo "/data/nfs *(rw,sync,all_squash,anonuid=1000,anongid=1000)" >> /etc/exports
3、加载NFS配置
[root@k8s-node02 ~]# exportfs -r
# 验证
[root@k8s-node02 ~]# exportfs -s
/data/nfs *(sync,wdelay,hide,no_subtree_check,anonuid=1000,anongid=1000,sec=sys,rw,secure,root_squash,all_squash)
4、启动NFS
[root@k8s-node02 ~]# systemctl enable --now nfs-server rpcbind
如果是Ubuntu 系列,则采用下面命令
[root@k8s-node02 ~]# systemctl enable --now nfs-kernel-server
5、客户端安装客户端工具
# 客户端安装客户端工具
[root@k8s-node01 ~]# yum install nfs-utils -y
[root@k8s-master01 ~]# yum install nfs-utils -y
如果是Ubuntu 系列,则采用下面命令
[root@k8s-node01 ~]# apt install nfs-common -y
[root@k8s-master01 ~]# apt install nfs-common -y
5.3.1.2 安装CSI¶
1、下载安装文件
[root@k8s-master01 ~]# git clone https://gitee.com/jeckjohn/csi-driver-nfs.git
2、安装CSI
[root@k8s-master01 ~]# cd csi-driver-nfs/
[root@k8s-master01 csi-driver-nfs]# sed -i "s#registry.k8s.io#k8s.m.daocloud.io#g" deploy/v4.9.0/*.yaml
[root@k8s-master01 csi-driver-nfs]# ./deploy/install-driver.sh v4.9.0 local
use local deploy
Installing NFS CSI driver, version: v4.9.0 ...
serviceaccount/csi-nfs-controller-sa created
serviceaccount/csi-nfs-node-sa created
clusterrole.rbac.authorization.k8s.io/nfs-external-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-provisioner-binding created
csidriver.storage.k8s.io/nfs.csi.k8s.io created
deployment.apps/csi-nfs-controller created
daemonset.apps/csi-nfs-node created
NFS CSI driver installed successfully.
3、查看pod状态
[root@k8s-master01 csi-driver-nfs]# kgp -n kube-system | grep csi-nfs
csi-nfs-controller-5c9687ccf5-l9fhp 4/4 Running 2 (5m26s ago) 6m13s
csi-nfs-node-4gnj9 3/3 Running 0 6m13s
csi-nfs-node-ccww4 3/3 Running 1 (5m22s ago) 6m13s
csi-nfs-node-rnqpn 3/3 Running 0 6m13s
4、查看CSI
[root@k8s-master01 csi-driver-nfs]# kg csidriver
NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE
nfs.csi.k8s.io false false false <unset> false Persistent 6m42s
5.3.1.3 创建SC指向CSI¶
1、在master01主机(10.0.0.20)上更改sc的配置
[root@k8s-master01 ~]# cd csi-driver-nfs/
# 添加nfs主机信息
server: 10.0.0.22
share: /data/nfs
# 修改后的文件内容如下
[root@k8s-master01 csi-driver-nfs]# vim deploy/v4.9.0/storageclass.yaml
[root@k8s-master01 csi-driver-nfs]# cat deploy/v4.9.0/storageclass.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.22
share: /data/nfs
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
- nfsvers=4.1
2、创建sc并查看
[root@k8s-master01 csi-driver-nfs]# kaf deploy/v4.9.0/storageclass.yaml
[root@k8s-master01 csi-driver-nfs]# kg sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 19s
5.3.2 创建redis集群¶
1、确认当前环境是否存在污点信息
[root@k8s-master01 ~]# kd node | grep Taints
Taints: <none>
Taints: <none>
Taints: <none>
2、创建redis集群的资源文件
[root@k8s-master01 ~]# mkdir operators
[root@k8s-master01 ~]# cd operators/
[root@k8s-master01 operators]# vim redis-cluster.yaml
apiVersion: redis.redis.opstreelabs.in/v1beta1
kind: RedisCluster
metadata:
name: redis-cluster
namespace: public-service
spec:
clusterSize: 3
clusterVersion: v7
securityContext:
runAsUser: 1000
fsGroup: 1000
persistenceEnabled: true
kubernetesConfig:
image: registry.cn-hangzhou.aliyuncs.com/github_images1024/redis:v7.0.15
imagePullPolicy: IfNotPresent
storage:
volumeClaimTemplate:
spec:
storageClassName: nfs-csi
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
2、创建redis集群
[root@k8s-master01 ~]# k create ns public-service
[root@k8s-master01 ~]# kaf redis-cluster.yaml
3、查看资源创建情况
查看pod
[root@k8s-master01 operators]# kgp -n public-service
NAME READY STATUS RESTARTS AGE
redis-cluster-follower-0 1/1 Running 0 10s
redis-cluster-follower-1 1/1 Running 0 7s
redis-cluster-follower-2 1/1 Running 0 4s
redis-cluster-leader-0 1/1 Running 0 18s
redis-cluster-leader-1 1/1 Running 0 16s
redis-cluster-leader-2 1/1 Running 0 13s
查看rediscluster状态
[root@k8s-master01 operators]# kg rediscluster -n public-service
NAME CLUSTERSIZE READYLEADERREPLICAS READYFOLLOWERREPLICAS
redis-cluster 3 3 3
查看redis集群状态
[root@k8s-master01 operators]# k exec -it redis-cluster-leader-0 -n public-service -- bash
redis-cluster-leader-0:/data$ redis-cli
# 查看集群信息
127.0.0.1:6379> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:3
cluster_my_epoch:1
cluster_stats_messages_ping_sent:790
cluster_stats_messages_pong_sent:802
cluster_stats_messages_sent:1592
cluster_stats_messages_ping_received:799
cluster_stats_messages_pong_received:790
cluster_stats_messages_meet_received:3
cluster_stats_messages_received:1592
total_cluster_links_buffer_limit_exceeded:0
# 查看集群节点信息,观察到为3个主节点,3个副节点
127.0.0.1:6379> CLUSTER NODES
61dd14cdb8acf54c1d45a436284fe4625036a46e 192.168.85.209:6379@16379,redis-cluster-follower-2 slave 202d715abaa4ad20adf571d1aa0fe29d847cf492 0 1743125655060 3 connected
4df94ed4a4f815195760df93e664305b7f884a83 192.168.32.144:6379@16379,redis-cluster-leader-0 myself,master - 0 1743125654000 1 connected 0-5460
32d1ca3d48a99e9f0abee59e992ca883bff004fa 192.168.58.250:6379@16379,redis-cluster-leader-1 master - 0 1743125656066 2 connected 5461-10922
a6d400e1d2e5045229fac6258f70d9c9a501b1a0 192.168.32.145:6379@16379,redis-cluster-follower-0 slave 4df94ed4a4f815195760df93e664305b7f884a83 0 1743125655059 1 connected
a3c6cd32aa80b9ed4387092712790bb3eb2947d0 192.168.58.251:6379@16379,redis-cluster-follower-1 slave 32d1ca3d48a99e9f0abee59e992ca883bff004fa 0 1743125655564 2 connected
202d715abaa4ad20adf571d1aa0fe29d847cf492 192.168.85.218:6379@16379,redis-cluster-leader-2 master - 0 1743125655000 3 connected 10923-16383
4、创建数据
说明:当客户端访问 Redis 集群时,如果请求的键(Key)不在当前连接的节点上,节点会返回
MOVED或ASK错误,指示客户端将请求重定向到正确的节点。
[root@k8s-master01 operators]# k exec -it redis-cluster-leader-0 -n public-service -- bash
redis-cluster-leader-0:/data$ redis-cli
# 下面信息提示我们要去指定节点进行数据存储,从上面集群节点信息查看是这个节点redis-cluster-leader-2 master
127.0.0.1:6379> set a 1
(error) MOVED 15495 192.168.85.218:6379
127.0.0.1:6379> exit
# 当然可以使用-c参数实现自动追踪,观察到追踪成功
redis-cluster-leader-0:/data$ redis-cli -c
127.0.0.1:6379> set a 1
-> Redirected to slot [15495] located at 192.168.85.218:6379
OK
192.168.85.218:6379> get a
"1"
5.3.3 设置Redis集群密码¶
1、使用Secret存储Redis密码
# 创建yaml文件
[root@k8s-master01 operators]# vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: redis-secret
namespace: public-service
stringData:
password: zq
type: Opaque
# 应用yaml文件
[root@k8s-master01 operators]# kaf secret.yaml
# 验证
[root@k8s-master01 operators]# kg secret -n public-service
NAME TYPE DATA AGE
redis-secret Opaque 1 11s
2、更新Redis集群配置
主要添加如下内容
redisSecret:
name: redis-secret
key: password
完整配置文件如下:
[root@k8s-master01 operators]# vim redis-cluster.yaml
apiVersion: redis.redis.opstreelabs.in/v1beta1
kind: RedisCluster
metadata:
name: redis-cluster
namespace: public-service
spec:
clusterSize: 3
clusterVersion: v7
securityContext:
runAsUser: 1000
fsGroup: 1000
persistenceEnabled: true
kubernetesConfig:
redisSecret:
name: redis-secret
key: password
image: registry.cn-hangzhou.aliyuncs.com/github_images1024/redis:v7.0.15
imagePullPolicy: IfNotPresent
storage:
volumeClaimTemplate:
spec:
storageClassName: nfs-csi
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
3、重新创建集群
这里注意:不能直接更新集群,只能删除后进行重建
# 删除集群
[root@k8s-master01 operators]# k delete -f redis-cluster.yaml
# 重新创建集群
[root@k8s-master01 operators]# kaf redis-cluster.yaml
# 查看pod
[root@k8s-master01 operators]# kgp -n public-service
NAME READY STATUS RESTARTS AGE
redis-cluster-follower-0 1/1 Running 0 62s
redis-cluster-follower-1 1/1 Running 0 59s
redis-cluster-follower-2 1/1 Running 0 56s
redis-cluster-leader-0 1/1 Running 0 70s
redis-cluster-leader-1 1/1 Running 0 67s
redis-cluster-leader-2 1/1 Running 0 64s
4、创建测试数据,并进行查看
[root@k8s-master01 operators]# k exec -it redis-cluster-leader-0 -n public-service -- bash
redis-cluster-leader-0:/data$ redis-cli -c -a zq
127.0.0.1:6379> set a 1
-> Redirected to slot [15495] located at 192.168.85.215:6379
OK
192.168.85.215:6379> get a
"1"
192.168.85.215:6379> set b 2
-> Redirected to slot [3300] located at 192.168.32.148:6379
OK
192.168.32.148:6379> get b
"2"
5.3.4 在k8s外部访问Redis集群¶
如果需要在K8s外部访问Redis集群(生产环境不推荐),就要把Redis集群暴露出去,此时可以把Service更改为NodePort
1、更新Redis集群配置
主要添加如下内容
service:
serviceType: NodePort
完整配置文件如下:
[root@k8s-master01 operators]# vim redis-cluster.yaml
apiVersion: redis.redis.opstreelabs.in/v1beta1
kind: RedisCluster
metadata:
name: redis-cluster
namespace: public-service
spec:
clusterSize: 3
clusterVersion: v7
securityContext:
runAsUser: 1000
fsGroup: 1000
persistenceEnabled: true
kubernetesConfig:
service:
serviceType: NodePort
redisSecret:
name: redis-secret
key: password
image: registry.cn-hangzhou.aliyuncs.com/github_images1024/redis:v7.0.15
imagePullPolicy: IfNotPresent
storage:
volumeClaimTemplate:
spec:
storageClassName: nfs-csi
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
2、重新应用
[root@k8s-master01 operators]# kaf redis-cluster.yaml
查看pod
[root@k8s-master01 operators]# kgp -n public-service
NAME READY STATUS RESTARTS AGE
redis-cluster-follower-0 1/1 Running 0 78s
redis-cluster-follower-1 1/1 Running 0 80s
redis-cluster-follower-2 1/1 Running 0 82s
redis-cluster-leader-0 1/1 Running 0 88s
redis-cluster-leader-1 1/1 Running 0 90s
redis-cluster-leader-2 1/1 Running 0 92s
查看svc
# 观察到设置为NodePort后,每个redis节点都暴露了端口号
[root@k8s-master01 operators]# kg svc -n public-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-cluster-follower ClusterIP 10.101.45.112 <none> 6379/TCP 27s
redis-cluster-follower-0 NodePort 10.102.12.189 <none> 6379:31806/TCP,16379:31516/TCP 27s
redis-cluster-follower-1 NodePort 10.110.240.68 <none> 6379:31512/TCP,16379:32749/TCP 26s
redis-cluster-follower-2 NodePort 10.106.144.153 <none> 6379:30821/TCP,16379:30354/TCP 26s
redis-cluster-follower-additional NodePort 10.108.169.155 <none> 6379:32525/TCP 26s
redis-cluster-follower-headless ClusterIP None <none> 6379/TCP 28s
redis-cluster-leader ClusterIP 10.105.147.223 <none> 6379/TCP 42s
redis-cluster-leader-0 NodePort 10.98.20.1 <none> 6379:31589/TCP,16379:31801/TCP 42s
redis-cluster-leader-1 NodePort 10.103.139.173 <none> 6379:30382/TCP,16379:31608/TCP 42s
redis-cluster-leader-2 NodePort 10.111.64.156 <none> 6379:30607/TCP,16379:30929/TCP 42s
redis-cluster-leader-additional NodePort 10.111.62.31 <none> 6379:32030/TCP 41s
redis-cluster-leader-headless ClusterIP None <none> 6379/TCP 42s
3、进入redis集群查看
[root@k8s-master01 operators]# k exec -it redis-cluster-leader-0 -n public-service -- bash
redis-cluster-leader-0:/data$ redis-cli -c -a zq
127.0.0.1:6379> set a 1
127.0.0.1:6379> get a
"1"
# 查看集群节点,观察到都换成节点IP:端口号
127.0.0.1:6379> CLUSTER NODES
5.3.5 Redis集群卸载¶
卸载Redis集群
# 删除pod及PVC
[root@k8s-master01 operators]# k delete -f redis-cluster.yaml
六、使用Operator一键安装MySQL Cluster¶
6.1 MySQL Cluster介绍¶
6.1.1 MySQL Cluster简单介绍¶
MySQL NDB Cluster是一个分布式、高可用的数据库系统,适用于需要高并发读写、低延迟和高可用性的应用场景。MySQL NDB Cluster基于NDB(Network Database)存储引擎,并通过多个节点协同工作来提供数据的分布存储和故障恢复能力。
推荐Operator:https://operatorhub.io/operator/ndb-operator
仓库地址:https://github.com/mysql/mysql-ndb-operator
国内仓库:https://gitee.com/jeckjohn/mysql-ndb-operator
官方文档:https://dev.mysql.com/doc/ndb-operator/8.4/en/
6.1.2 MySQL Cluster集群架构¶
参考链接:https://dev.mysql.com/doc/ndb-operator/8.4/en/introduction.html

组件介绍:
- 管理节点:Management Node,负责管理和配置整个NDB Cluster。保存了NDB集群的配置信息,包括Data Node、SQL Node。管理节点不直接参与数据存储或事务处理,主要负责集群的管理和监控,确保集群的正常运行。
- 数据节点:Data Node,数据节点是集群中实际存储数据的节点,负责存储一部分数据,并且数据会在多个Data Node之间进行分区和复制,以实现高可用性和负载均衡。
- SQL节点:SQL Node,SQL Node是用户与NDB Cluster交互的主要入口,提供了标准的MySQL SQL接口,允许用户通过SQL查询、插入、更新和删除数据。
- NDBAPI:可以直接与NDB存储引擎进行交互的接口。
6.2 安装Operator和CRD¶
1、下载部署文件
[root@k8s-master01 ~]# git clone https://gitee.com/jeckjohn/mysql-ndb-operator.git
2、创建Operator
[root@k8s-master01 ~]# cd mysql-ndb-operator/
[root@k8s-master01 mysql-ndb-operator]# kaf deploy/manifests/ndb-operator.yaml
3、验证查看
查看pod
[root@k8s-master01 mysql-ndb-operator]# kgp -n ndb-operator
NAME READY STATUS RESTARTS AGE
ndb-operator-app-f954dcb7c-gxhm2 1/1 Running 0 53s
ndb-operator-webhook-server-67c8d77f78-nl7n6 1/1 Running 0 53s
查看crd
[root@k8s-master01 mysql-ndb-operator]# kubectl api-resources | grep mysql
ndbclusters ndb,ndbc mysql.oracle.com/v1 true NdbCluster
6.3 安装NDB Cluster¶
参考链接:https://dev.mysql.com/doc/ndb-operator/8.4/en/deployment-configuration.html
6.3.1 环境准备¶
6.3.1.1 搭建NFS¶
1、在10.0.0.22主机上搭建NFS
[root@k8s-node02 ~]# yum install nfs-utils rpcbind -y
如果是Ubuntu 系列,则采用下面命令
[root@k8s-node02 ~]# apt install nfs-kernel-server -y
2、配置共享目录
[root@k8s-node02 ~]# mkdir /data/nfs -p
[root@k8s-node02 ~]# chmod -R 775 /data/nfs
[root@k8s-node02 ~]# echo "/data/nfs/ 10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
3、加载NFS配置
[root@k8s-node02 ~]# exportfs -r
# 验证
[root@k8s-node02 ~]# exportfs -s
/data/nfs 10.0.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
4、启动NFS
[root@k8s-node02 ~]# systemctl enable --now nfs-server rpcbind
如果是Ubuntu 系列,则采用下面命令
[root@k8s-node02 ~]# systemctl enable --now nfs-kernel-server
5、客户端安装客户端工具
# 客户端安装客户端工具
[root@k8s-node01 ~]# yum install nfs-utils -y
[root@k8s-master01 ~]# yum install nfs-utils -y
如果是Ubuntu 系列,则采用下面命令
[root@k8s-node01 ~]# apt install nfs-common -y
[root@k8s-master01 ~]# apt install nfs-common -y
6.3.1.2 安装CSI¶
1、下载安装文件
[root@k8s-master01 ~]# git clone https://gitee.com/jeckjohn/csi-driver-nfs.git
2、安装CSI
[root@k8s-master01 ~]# cd csi-driver-nfs/
[root@k8s-master01 csi-driver-nfs]# sed -i "s#registry.k8s.io#k8s.m.daocloud.io#g" deploy/v4.9.0/*.yaml
[root@k8s-master01 csi-driver-nfs]# ./deploy/install-driver.sh v4.9.0 local
use local deploy
Installing NFS CSI driver, version: v4.9.0 ...
serviceaccount/csi-nfs-controller-sa created
serviceaccount/csi-nfs-node-sa created
clusterrole.rbac.authorization.k8s.io/nfs-external-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-provisioner-binding created
csidriver.storage.k8s.io/nfs.csi.k8s.io created
deployment.apps/csi-nfs-controller created
daemonset.apps/csi-nfs-node created
NFS CSI driver installed successfully.
3、查看pod状态
[root@k8s-master01 csi-driver-nfs]# kgp -n kube-system | grep csi-nfs
csi-nfs-controller-5c9687ccf5-l9fhp 4/4 Running 2 (5m26s ago) 6m13s
csi-nfs-node-4gnj9 3/3 Running 0 6m13s
csi-nfs-node-ccww4 3/3 Running 1 (5m22s ago) 6m13s
csi-nfs-node-rnqpn 3/3 Running 0 6m13s
4、查看CSI
[root@k8s-master01 csi-driver-nfs]# kg csidriver
NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE
nfs.csi.k8s.io false false false <unset> false Persistent 6m42s
6.3.1.3 创建SC指向CSI¶
1、在master01主机(10.0.0.20)上更改sc的配置
[root@k8s-master01 ~]# cd csi-driver-nfs/
# 添加nfs主机信息
server: 10.0.0.22
share: /data/nfs
# 修改后的文件内容如下
[root@k8s-master01 csi-driver-nfs]# vim deploy/v4.9.0/storageclass.yaml
[root@k8s-master01 csi-driver-nfs]# cat deploy/v4.9.0/storageclass.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.22
share: /data/nfs
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
- nfsvers=4.1
2、创建sc并查看
[root@k8s-master01 csi-driver-nfs]# kaf deploy/v4.9.0/storageclass.yaml
[root@k8s-master01 csi-driver-nfs]# kg sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 19s
6.3.2 创建MySQL集群¶
1、创建一个NDB Cluster
# 创建ns
[root@k8s-master01 ~]# k create ns ndb-cluster
# 定义yaml文件
[root@k8s-master01 ~]# vim ndb-cluster.yaml
apiVersion: mysql.oracle.com/v1
kind: NdbCluster
metadata:
name: example-ndb
namespace: ndb-cluster
spec:
image: registry.cn-hangzhou.aliyuncs.com/github_images1024/community-cluster:9.1.0
redundancyLevel: 1 # 指定数据副本的数量,生产环境建议≥2
dataNode:
nodeCount: 1
pvcSpec:
storageClassName: nfs-csi
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
mysqlNode:
nodeCount: 1
pvcSpec:
storageClassName: nfs-csi
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
# 创建ndb-cluster
[root@k8s-master01 ~]# kaf ndb-cluster.yaml
2、验证查看,观察到创建成功
# 查看集群状态
[root@k8s-master01 ~]# kg ndbcluster -n ndb-cluster
NAME REPLICA MANAGEMENT NODES DATA NODES MYSQL SERVERS AGE UP-TO-DATE
example-ndb 1 Ready:1/1 Ready:1/1 Ready:1/1 80s True
# 查看pod状态
[root@k8s-master01 ~]# kgp -n ndb-cluster
NAME READY STATUS RESTARTS AGE
example-ndb-mgmd-0 1/1 Running 0 66s
example-ndb-mysqld-0 1/1 Running 0 45s
example-ndb-ndbmtd-0 1/1 Running 0 57s
# 查看svc
[root@k8s-master01 ~]# kg svc -n ndb-cluster
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-ndb-mgmd ClusterIP 10.106.221.140 <none> 1186/TCP 7m50s
example-ndb-mysqld ClusterIP 10.109.227.86 <none> 3306/TCP 7m29s
example-ndb-ndbmtd ClusterIP None <none> 1186/TCP 7m41s
6.3.3 MySQL集群测试¶
1、登录到SQL节点执行show命令查看集群节点的状态信息
[root@k8s-master01 ~]# k exec -it example-ndb-mysqld-0 -n ndb-cluster -- bash
bash-5.1# ndb_mgm -c example-ndb-mgmd
ndb_mgm> show
Connected to management server at example-ndb-mgmd port 1186 (using cleartext)
Cluster Configuration
---------------------
[ndbd(NDB)] 1 node(s)
id=2 @192.168.85.218 (mysql-9.1.0 ndb-9.1.0, Nodegroup: 0, *)
[ndb_mgmd(MGM)] 1 node(s)
id=1 @192.168.58.197 (mysql-9.1.0 ndb-9.1.0)
[mysqld(API)] 6 node(s)
id=147 (not connected, accepting connect from any host)
id=148 @192.168.58.198 (mysql-9.1.0 ndb-9.1.0)
id=149 (not connected, accepting connect from example-ndb-mysqld-1.example-ndb-mysqld.ndb-cluster.svc.cluster.local)
id=150 (not connected, accepting connect from example-ndb-mysqld-2.example-ndb-mysqld.ndb-cluster.svc.cluster.local)
id=151 (not connected, accepting connect from any host)
id=152 (not connected, accepting connect from any host)
2、也可以通过MySQL客户端链接集群
查看集群的访问密码为gBINI2F8smUdrA2b
[root@k8s-master01 ~]# kubectl -n ndb-cluster get secret example-ndb-mysqld-root-password -o jsonpath='{.data.password}' | base64 -d
gBINI2F8smUdrA2b
登录到MySQL查看所有的数据库信息
[root@k8s-master01 ~]# k exec -it example-ndb-mysqld-0 -n ndb-cluster -- bash
bash-5.1# mysql -h example-ndb-mysqld -uroot -pgBINI2F8smUdrA2b
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| ndbinfo |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
6.3.4 在k8s外部访问MySQL集群¶
如果想要在集群外部访问,可以创建一个SOL Node NodePort类型的Service
1、定义Service的文件
[root@k8s-master01 ~]# kg svc example-ndb-mysqld -n ndb-cluster -oyaml > ndbcluster-svc-np.yaml
[root@k8s-master01 ~]# vim ndbcluster-svc-np.yaml
apiVersion: v1
kind: Service
metadata:
labels:
mysql.oracle.com/resource-type: mysqld-service
mysql.oracle.com/v1: example-ndb
name: example-ndb-mysqld-np
namespace: ndb-cluster
spec:
ports:
- name: mysqld-service-port-0
port: 3306
protocol: TCP
targetPort: 3306
publishNotReadyAddresses: true
selector:
mysql.oracle.com/node-type: mysqld
mysql.oracle.com/v1: example-ndb
sessionAffinity: None
type: NodePort
2、创建该Service
[root@k8s-master01 ~]# kaf ndbcluster-svc-np.yaml
3、查看暴露的端口为30210
[root@k8s-master01 ~]# kg svc -n ndb-cluster | grep example-ndb-mysqld-np
example-ndb-mysqld-np NodePort 10.105.254.8 <none> 3306:30210/TCP 28s
4、测试登录到数据库,观察到已成功登录到数据库中
[root@k8s-master01 ~]# k exec -it example-ndb-mysqld-0 -n ndb-cluster -- bash
bash-5.1# mysql -h10.0.0.20 -uroot -P30210 -pgBINI2F8smUdrA2b
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| ndbinfo |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
6.3.5 MySQL集群卸载¶
MySQL集群卸载
# 删除svc
[root@k8s-master01 ~]# k delete -f ndbcluster-svc-np.yaml
# 删除mysql集群
[root@k8s-master01 ~]# k delete -f ndb-cluster.yaml
# 删除ns
[root@k8s-master01 ~]# k delete ns ndb-cluster