一、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使用步骤和工作流程

Day021-K8s资源管理与扩展-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集群架构

cluster-redis

一、数据分片机制:哈希槽(Hash Slot)

  1. 哈希槽总数 Redis Cluster 将数据划分为 16384 个哈希槽,每个键通过 CRC16 算法计算哈希值,再对 16384 取模得到对应的槽位。
  2. 槽分配规则
  3. 每个主节点(Master)负责一部分槽位,例如:
    • 节点 A 负责槽 0-5460
    • 节点 B 负责槽 5461-10922
    • 节点 C 负责槽 10923-16383
  4. 槽分配信息通过 CLUSTER ADDSLOTS 命令手动或自动完成。
  5. 动态重分片 支持在线迁移槽位,允许集群动态扩展或缩容。例如,添加新节点后,可重新分配槽位以实现负载均衡。

二、节点角色与职责

  1. 主节点(Master)
  2. 处理读写请求,负责其分配的哈希槽。
  3. 参与集群状态投票(如故障检测、新主节点选举)。
  4. 从节点(Slave)
  5. 复制主节点的数据,提供数据冗余
  6. 在主节点故障时,通过选举机制升级为新的主节点(自动故障转移)。
  7. 最小集群规模
  8. 至少需要 3 个主节点3 个从节点(共 6 节点)以实现高可用。

三、节点通信:Gossip 协议

  1. 通信机制
  2. 节点间通过 Gossip 协议 定期交换信息(如节点状态、槽位分布)。
  3. 消息类型包括 PING(检测存活)、PONG(响应)、FAIL(节点下线通知)等。
  4. 故障检测
  5. 若某节点在 cluster-node-timeout(默认 15 秒)内未响应,其他节点将其标记为 疑似下线(PFail)
  6. 超过半数主节点确认该节点下线后,标记为 已下线(Fail),触发故障转移。

四、客户端交互与重定向

  1. 智能客户端

  2. 客户端首次连接集群时,获取槽位分布信息并缓存。

  3. 直接向目标节点发送请求,减少重定向次数。

  4. 重定向机制

  5. MOVED 错误:键所属槽位已迁移到其他节点,客户端更新缓存并重试。

    plaintext

    复制

    MOVED 1234 192.168.1.2:6379

  6. ASK 错误:键所属槽位正在迁移中,客户端临时重定向到目标节点。

    plaintext

    复制

    ASK 1234 192.168.1.3:6379

五、故障转移与恢复

  1. 自动故障转移
  2. 当主节点下线时,其从节点发起选举(基于 Raft 算法)。
  3. 获得多数主节点投票的从节点升级为新主节点。
  4. 手动干预场景
  5. 网络分区恢复:需人工介入确认节点状态。
  6. 部分主节点永久故障:强制触发故障转移(CLUSTER FAILOVER)。

六、集群管理命令

命令 用途
CLUSTER MEET <ip> <port> 将新节点加入集群
CLUSTER ADDSLOTS <slot> 分配槽位给当前节点
CLUSTER REPLICATE <node-id> 将当前节点设置为某主节点的从节点
CLUSTER INFO 查看集群状态摘要
CLUSTER NODES 列出集群所有节点信息

七、架构优势与限制

  1. 优势
  2. 横向扩展:支持动态增加节点提升性能。
  3. 高可用性:自动故障转移确保服务连续性。
  4. 去中心化:无单点依赖,节点对等通信。
  5. 限制
  6. 不支持跨槽事务:涉及多个槽的 MULTI 操作无法保证原子性。
  7. 批量操作限制:如 MSET 需确保所有键在同一槽。
  8. 迁移复杂性:槽位迁移期间需处理 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)不在当前连接的节点上,节点会返回 MOVEDASK 错误,指示客户端将请求重定向到正确的节点。

[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

MySQL Cluster集群架构

组件介绍:

  • 管理节点: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