溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何在K8s上部署Redis集群

發(fā)布時(shí)間:2021-03-19 13:43:59 來源:億速云 閱讀:2472 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章將為大家詳細(xì)講解有關(guān)如何在K8s上部署Redis集群,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

一、前言
架構(gòu)原理:每個(gè)Master都可以擁有多個(gè)Slave。當(dāng)Master下線后,Redis集群會(huì)從多個(gè)Slave中選舉出一個(gè)新的Master作為替代,而舊Master重新上線后變成新Master的Slave。

二、準(zhǔn)備操作
本次部署主要基于該項(xiàng)目:

https://github.com/zuxqoj/kubernetes-redis-cluster

其包含了兩種部署Redis集群的方式:

StatefulSet
Service&Deployment

兩種方式各有優(yōu)劣,對(duì)于像Redis、Mongodb、Zookeeper等有狀態(tài)的服務(wù),使用StatefulSet是首選方式。本文將主要介紹如何使用StatefulSet進(jìn)行Redis集群的部署。

三、StatefulSet簡介
RC、Deployment、DaemonSet都是面向無狀態(tài)的服務(wù),它們所管理的Pod的IP、名字,啟停順序等都是隨機(jī)的,而StatefulSet是什么?顧名思義,有狀態(tài)的集合,管理所有有狀態(tài)的服務(wù),比如MySQL、MongoDB集群等。
StatefulSet本質(zhì)上是Deployment的一種變體,在v1.9版本中已成為GA版本,它為了解決有狀態(tài)服務(wù)的問題,它所管理的Pod擁有固定的Pod名稱,啟停順序,在StatefulSet中,Pod名字稱為網(wǎng)絡(luò)標(biāo)識(shí)(hostname),還必須要用到共享存儲(chǔ)。
在Deployment中,與之對(duì)應(yīng)的服務(wù)是service,而在StatefulSet中與之對(duì)應(yīng)的headless service,headless service,即無頭服務(wù),與service的區(qū)別就是它沒有Cluster IP,解析它的名稱時(shí)將返回該Headless Service對(duì)應(yīng)的全部Pod的Endpoint列表。
除此之外,StatefulSet在Headless Service的基礎(chǔ)上又為StatefulSet控制的每個(gè)Pod副本創(chuàng)建了一個(gè)DNS域名,這個(gè)域名的格式為:

$(podname).(headless server name)   
FQDN: $(podname).(headless server name).namespace.svc.cluster.local

也即是說,對(duì)于有狀態(tài)服務(wù),我們最好使用固定的網(wǎng)絡(luò)標(biāo)識(shí)(如域名信息)來標(biāo)記節(jié)點(diǎn),當(dāng)然這也需要應(yīng)用程序的支持(如Zookeeper就支持在配置文件中寫入主機(jī)域名)。
StatefulSet基于Headless Service(即沒有Cluster IP的Service)為Pod實(shí)現(xiàn)了穩(wěn)定的網(wǎng)絡(luò)標(biāo)志(包括Pod的hostname和DNS Records),在Pod重新調(diào)度后也保持不變。同時(shí),結(jié)合PV/PVC,StatefulSet可以實(shí)現(xiàn)穩(wěn)定的持久化存儲(chǔ),就算Pod重新調(diào)度后,還是能訪問到原先的持久化數(shù)據(jù)。
以下為使用StatefulSet部署Redis的架構(gòu),無論是Master還是Slave,都作為StatefulSet的一個(gè)副本,并且數(shù)據(jù)通過PV進(jìn)行持久化,對(duì)外暴露為一個(gè)Service,接受客戶端請(qǐng)求。

四、部署過程
本文參考項(xiàng)目的README中,簡要介紹了基于StatefulSet的Redis創(chuàng)建步驟:

1.創(chuàng)建NFS存儲(chǔ)
2.創(chuàng)建PV
3.創(chuàng)建PVC
4.創(chuàng)建Configmap
5.創(chuàng)建headless服務(wù)
6.創(chuàng)建Redis StatefulSet
7.初始化Redis集群

這里,我將參考如上步驟,實(shí)踐操作并詳細(xì)介紹Redis集群的部署過程。文中會(huì)涉及到很多K8S的概念,希望大家能提前了解學(xué)習(xí)

1.創(chuàng)建NFS存儲(chǔ)
創(chuàng)建NFS存儲(chǔ)主要是為了給Redis提供穩(wěn)定的后端存儲(chǔ),當(dāng)Redis的Pod重啟或遷移后,依然能獲得原先的數(shù)據(jù)。這里,我們先要?jiǎng)?chuàng)建NFS,然后通過使用PV為Redis掛載一個(gè)遠(yuǎn)程的NFS路徑。

安裝NFS

yum -y install nfs-utils(主包提供文件系統(tǒng))
yum -y install rpcbind(提供rpc協(xié)議)

然后,新增/etc/exports文件,用于設(shè)置需要共享的路徑:

[root@ftp pv3]# cat /etc/exports
/usr/local/k8s/redis/pv1 192.168.0.0/24(rw,sync,no_root_squash)
/usr/local/k8s/redis/pv2 192.168.0.0/24(rw,sync,no_root_squash)
/usr/local/k8s/redis/pv3 192.168.0.0/24(rw,sync,no_root_squash)
/usr/local/k8s/redis/pv4 192.168.0.0/24(rw,sync,no_root_squash)
/usr/local/k8s/redis/pv5 192.168.0.0/24(rw,sync,no_root_squash)
/usr/local/k8s/redis/pv6 192.168.0.0/24(rw,sync,no_root_squash)

如何在K8s上部署Redis集群
創(chuàng)建相應(yīng)目錄

[root@ftp quizii]# mkdir -p /usr/local/k8s/redis/pv{1..6}

接著,啟動(dòng)NFS和rpcbind服務(wù):

systemctl restart rpcbind
systemctl restart nfs
systemctl enable nfs
[root@ftp pv3]# exportfs -v
/usr/local/k8s/redis/pv1
		192.168.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/redis/pv2
		192.168.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/redis/pv3
		192.168.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/redis/pv4
		192.168.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/redis/pv5
		192.168.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/usr/local/k8s/redis/pv6
		192.168.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)

客戶端

yum -y install nfs-utils

查看存儲(chǔ)端共享

[root@node2 ~]# showmount -e 192.168.0.222
Export list for 192.168.0.222:
/usr/local/k8s/redis/pv6 192.168.0.0/24
/usr/local/k8s/redis/pv5 192.168.0.0/24
/usr/local/k8s/redis/pv4 192.168.0.0/24
/usr/local/k8s/redis/pv3 192.168.0.0/24
/usr/local/k8s/redis/pv2 192.168.0.0/24
/usr/local/k8s/redis/pv1 192.168.0.0/24

創(chuàng)建PV
每一個(gè)Redis Pod都需要一個(gè)獨(dú)立的PV來存儲(chǔ)自己的數(shù)據(jù),因此可以創(chuàng)建一個(gè)pv.yaml文件,包含6個(gè)PV:

[root@master redis]# cat pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
spec:
  capacity:
    storage: 200M
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.0.222
    path: "/usr/local/k8s/redis/pv1"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-vp2
spec:
  capacity:
    storage: 200M
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.0.222
    path: "/usr/local/k8s/redis/pv2"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv3
spec:
  capacity:
    storage: 200M
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.0.222
    path: "/usr/local/k8s/redis/pv3"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv4
spec:
  capacity:
    storage: 200M
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.0.222
    path: "/usr/local/k8s/redis/pv4"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv5
spec:
  capacity:
    storage: 200M
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.0.222
    path: "/usr/local/k8s/redis/pv5"

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv6
spec:
  capacity:
    storage: 200M
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.0.222
    path: "/usr/local/k8s/redis/pv6"

如上,可以看到所有PV除了名稱和掛載的路徑外都基本一致。執(zhí)行創(chuàng)建即可:

[root@master redis]#kubectl create -f pv.yaml 
persistentvolume "nfs-pv1" created
persistentvolume "nfs-pv2" created
persistentvolume "nfs-pv3" created
persistentvolume "nfs-pv4" created
persistentvolume "nfs-pv5" created
persistentvolume "nfs-pv6" created

2.創(chuàng)建Configmap
這里,我們可以直接將Redis的配置文件轉(zhuǎn)化為Configmap,這是一種更方便的配置讀取方式。配置文件redis.conf如下

[root@master redis]# cat redis.conf 
appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

創(chuàng)建名為redis-conf的Configmap:

kubectl create configmap redis-conf --from-file=redis.conf

查看創(chuàng)建的configmap:

[root@master redis]# kubectl describe cm redis-conf
Name:         redis-conf
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis.conf:
----
appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

Events:  <none>

如上,redis.conf中的所有配置項(xiàng)都保存到redis-conf這個(gè)Configmap中。

3.創(chuàng)建Headless service
Headless service是StatefulSet實(shí)現(xiàn)穩(wěn)定網(wǎng)絡(luò)標(biāo)識(shí)的基礎(chǔ),我們需要提前創(chuàng)建。準(zhǔn)備文件headless-service.yml如下:

[root@master redis]# cat headless-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis-service
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    port: 6379
  clusterIP: None
  selector:
    app: redis
    appCluster: redis-cluster

創(chuàng)建:

kubectl create -f headless-service.yml

查看:
如何在K8s上部署Redis集群
可以看到,服務(wù)名稱為redis-service,其CLUSTER-IP為None,表示這是一個(gè)“無頭”服務(wù)。

4.創(chuàng)建Redis 集群節(jié)點(diǎn)
創(chuàng)建好Headless service后,就可以利用StatefulSet創(chuàng)建Redis 集群節(jié)點(diǎn),這也是本文的核心內(nèi)容。我們先創(chuàng)建redis.yml文件:

[root@master redis]# cat redis.yaml 
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: redis-app
spec:
  serviceName: "redis-service"
  replicas: 6
  template:
    metadata:
      labels:
        app: redis
        appCluster: redis-cluster
    spec:
      terminationGracePeriodSeconds: 20
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - redis
              topologyKey: kubernetes.io/hostname
      containers:
      - name: redis
        image: redis
        command:
          - "redis-server"
        args:
          - "/etc/redis/redis.conf"
          - "--protected-mode"
          - "no"
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
        ports:
            - name: redis
              containerPort: 6379
              protocol: "TCP"
            - name: cluster
              containerPort: 16379
              protocol: "TCP"
        volumeMounts:
          - name: "redis-conf"
            mountPath: "/etc/redis"
          - name: "redis-data"
            mountPath: "/var/lib/redis"
      volumes:
      - name: "redis-conf"
        configMap:
          name: "redis-conf"
          items:
            - key: "redis.conf"
              path: "redis.conf"
  volumeClaimTemplates:
  - metadata:
      name: redis-data
    spec:
      accessModes: [ "ReadWriteMany" ]
      resources:
        requests:
          storage: 200M

如上,總共創(chuàng)建了6個(gè)Redis節(jié)點(diǎn)(Pod),其中3個(gè)將用于master,另外3個(gè)分別作為master的slave;Redis的配置通過volume將之前生成的redis-conf這個(gè)Configmap,掛載到了容器的/etc/redis/redis.conf;Redis的數(shù)據(jù)存儲(chǔ)路徑使用volumeClaimTemplates聲明(也就是PVC),其會(huì)綁定到我們先前創(chuàng)建的PV上。
這里有一個(gè)關(guān)鍵概念——Affinity,請(qǐng)參考官方文檔詳細(xì)了解。其中,podAntiAffinity表示反親和性,其決定了某個(gè)pod不可以和哪些Pod部署在同一拓?fù)溆颍梢杂糜趯⒁粋€(gè)服務(wù)的POD分散在不同的主機(jī)或者拓?fù)溆蛑?,提高服?wù)本身的穩(wěn)定性。
而PreferredDuringSchedulingIgnoredDuringExecution 則表示,在調(diào)度期間盡量滿足親和性或者反親和性規(guī)則,如果不能滿足規(guī)則,POD也有可能被調(diào)度到對(duì)應(yīng)的主機(jī)上。在之后的運(yùn)行過程中,系統(tǒng)不會(huì)再檢查這些規(guī)則是否滿足。
在這里,matchExpressions規(guī)定了Redis Pod要盡量不要調(diào)度到包含app為redis的Node上,也即是說已經(jīng)存在Redis的Node上盡量不要再分配Redis Pod了。但是,由于我們只有三個(gè)Node,而副本有6個(gè),因此根據(jù)PreferredDuringSchedulingIgnoredDuringExecution,這些豌豆不得不得擠一擠,擠擠更健康~
另外,根據(jù)StatefulSet的規(guī)則,我們生成的Redis的6個(gè)Pod的hostname會(huì)被依次命名為 $(statefulset名稱)-$(序號(hào)) 如下圖所示:

[root@master redis]# kubectl get pods -o wide 
NAME                                            READY     STATUS      RESTARTS   AGE       IP             NODE            NOMINATED NODE
redis-app-0                                     1/1       Running     0          2h        172.17.24.3    192.168.0.144   <none>
redis-app-1                                     1/1       Running     0          2h        172.17.63.8    192.168.0.148   <none>
redis-app-2                                     1/1       Running     0          2h        172.17.24.8    192.168.0.144   <none>
redis-app-3                                     1/1       Running     0          2h        172.17.63.9    192.168.0.148   <none>
redis-app-4                                     1/1       Running     0          2h        172.17.24.9    192.168.0.144   <none>
redis-app-5                                     1/1       Running     0          2h        172.17.63.10   192.168.0.148   <none>

如上,可以看到這些Pods在部署時(shí)是以{0…N-1}的順序依次創(chuàng)建的。注意,直到redis-app-0狀態(tài)啟動(dòng)后達(dá)到Running狀態(tài)之后,redis-app-1 才開始啟動(dòng)。
同時(shí),每個(gè)Pod都會(huì)得到集群內(nèi)的一個(gè)DNS域名,格式為$(podname).$(service name).$(namespace).svc.cluster.local ,也即是:

redis-app-0.redis-service.default.svc.cluster.local
redis-app-1.redis-service.default.svc.cluster.local
...以此類推...

在K8S集群內(nèi)部,這些Pod就可以利用該域名互相通信。我們可以使用busybox鏡像的nslookup檢驗(yàn)這些域名:

[root@master redis]# kubectl exec -ti busybox -- nslookup redis-app-0.redis-service
Server:    10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local

Name:      redis-app-0.redis-service
Address 1: 172.17.24.3

可以看到, redis-app-0的IP為172.17.24.3。當(dāng)然,若Redis Pod遷移或是重啟(我們可以手動(dòng)刪除掉一個(gè)Redis Pod來測試),IP是會(huì)改變的,但是Pod的域名、SRV records、A record都不會(huì)改變。

另外可以發(fā)現(xiàn),我們之前創(chuàng)建的pv都被成功綁定了:

[root@master redis]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                            STORAGECLASS   REASON    AGE
nfs-pv1   200M       RWX            Retain           Bound     default/redis-data-redis-app-2                            3h
nfs-pv3   200M       RWX            Retain           Bound     default/redis-data-redis-app-4                            3h
nfs-pv4   200M       RWX            Retain           Bound     default/redis-data-redis-app-5                            3h
nfs-pv5   200M       RWX            Retain           Bound     default/redis-data-redis-app-1                            3h
nfs-pv6   200M       RWX            Retain           Bound     default/redis-data-redis-app-0                            3h
nfs-vp2   200M       RWX            Retain           Bound     default/redis-data-redis-app-3                            3h

5.初始化Redis集群

創(chuàng)建好6個(gè)Redis Pod后,我們還需要利用常用的Redis-tribe工具進(jìn)行集群的初始化

創(chuàng)建Ubuntu容器
由于Redis集群必須在所有節(jié)點(diǎn)啟動(dòng)后才能進(jìn)行初始化,而如果將初始化邏輯寫入Statefulset中,則是一件非常復(fù)雜而且低效的行為。這里,本人不得不稱贊一下原項(xiàng)目作者的思路,值得學(xué)習(xí)。也就是說,我們可以在K8S上創(chuàng)建一個(gè)額外的容器,專門用于進(jìn)行K8S集群內(nèi)部某些服務(wù)的管理控制。
這里,我們專門啟動(dòng)一個(gè)Ubuntu的容器,可以在該容器中安裝Redis-tribe,進(jìn)而初始化Redis集群,執(zhí)行:

kubectl run -it ubuntu --image=ubuntu --restart=Never /bin/bash

我們使用阿里云的Ubuntu源,執(zhí)行:

root@ubuntu:/# cat > /etc/apt/sources.list << EOF
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
 
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
> EOF

成功后,原項(xiàng)目要求執(zhí)行如下命令安裝基本的軟件環(huán)境:

apt-get update
apt-get install -y vim wget python2.7 python-pip redis-tools dnsutils

初始化集群
首先,我們需要安裝redis-trib

pip install redis-trib==0.5.1

然后,創(chuàng)建只有Master節(jié)點(diǎn)的集群:

redis-trib.py create \
  `dig +short redis-app-0.redis-service.default.svc.cluster.local`:6379 \
  `dig +short redis-app-1.redis-service.default.svc.cluster.local`:6379 \
  `dig +short redis-app-2.redis-service.default.svc.cluster.local`:6379

其次,為每個(gè)Master添加Slave

redis-trib.py replicate \
  --master-addr `dig +short redis-app-0.redis-service.default.svc.cluster.local`:6379 \
  --slave-addr `dig +short redis-app-3.redis-service.default.svc.cluster.local`:6379

redis-trib.py replicate \
  --master-addr `dig +short redis-app-1.redis-service.default.svc.cluster.local`:6379 \
  --slave-addr `dig +short redis-app-4.redis-service.default.svc.cluster.local`:6379

redis-trib.py replicate \
  --master-addr `dig +short redis-app-2.redis-service.default.svc.cluster.local`:6379 \
  --slave-addr `dig +short redis-app-5.redis-service.default.svc.cluster.local`:6379

至此,我們的Redis集群就真正創(chuàng)建完畢了,連到任意一個(gè)Redis Pod中檢驗(yàn)一下:

[root@master redis]# kubectl exec -it redis-app-2 /bin/bash
root@redis-app-2:/data# /usr/local/bin/redis-cli -c
127.0.0.1:6379> cluster nodes
5d3e77f6131c6f272576530b23d1cd7592942eec 172.17.24.3:6379@16379 master - 0 1559628533000 1 connected 0-5461
a4b529c40a920da314c6c93d17dc603625d6412c 172.17.63.10:6379@16379 master - 0 1559628531670 6 connected 10923-16383
368971dc8916611a86577a8726e4f1f3a69c5eb7 172.17.24.9:6379@16379 slave 0025e6140f85cb243c60c214467b7e77bf819ae3 0 1559628533672 4 connected
0025e6140f85cb243c60c214467b7e77bf819ae3 172.17.63.8:6379@16379 master - 0 1559628533000 2 connected 5462-10922
6d5ee94b78b279e7d3c77a55437695662e8c039e 172.17.24.8:6379@16379 myself,slave a4b529c40a920da314c6c93d17dc603625d6412c 0 1559628532000 5 connected
2eb3e06ce914e0e285d6284c4df32573e318bc01 172.17.63.9:6379@16379 slave 5d3e77f6131c6f272576530b23d1cd7592942eec 0 1559628533000 3 connected
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:6
cluster_my_epoch:6
cluster_stats_messages_ping_sent:14910
cluster_stats_messages_pong_sent:15139
cluster_stats_messages_sent:30049
cluster_stats_messages_ping_received:15139
cluster_stats_messages_pong_received:14910
cluster_stats_messages_received:30049
127.0.0.1:6379>

另外,還可以在NFS上查看Redis掛載的數(shù)據(jù):

[root@ftp pv3]# ll /usr/local/k8s/redis/pv3
total 12
-rw-r--r-- 1 root root  92 Jun  4 11:36 appendonly.aof
-rw-r--r-- 1 root root 175 Jun  4 11:36 dump.rdb
-rw-r--r-- 1 root root 794 Jun  4 11:49 nodes.conf

6.創(chuàng)建用于訪問Service
前面我們創(chuàng)建了用于實(shí)現(xiàn)StatefulSet的Headless Service,但該Service沒有Cluster Ip,因此不能用于外界訪問。所以,我們還需要?jiǎng)?chuàng)建一個(gè)Service,專用于為Redis集群提供訪問和負(fù)載均衡

[root@master redis]# cat redis-access-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis-access-service
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    protocol: "TCP"
    port: 6379
    targetPort: 6379
  selector:
    app: redis
    appCluster: redis-cluster

如上,該Service名稱為 redis-access-service,在K8S集群中暴露6379端口,并且會(huì)對(duì)labels nameapp: redisappCluster: redis-cluster的pod進(jìn)行負(fù)載均衡。

創(chuàng)建后查看:

[root@master redis]#  kubectl get svc redis-access-service -o wide
NAME                   TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE       SELECTOR
redis-access-service   ClusterIP   10.0.0.64    <none>        6379/TCP   2h        app=redis,appCluster=redis-cluster

如上,在K8S集群中,所有應(yīng)用都可以通過10.0.0.64 :6379來訪問Redis集群。當(dāng)然,為了方便測試,我們也可以為Service添加一個(gè)NodePort映射到物理機(jī)上,這里不再詳細(xì)介紹。

五、測試主從切換
在K8S上搭建完好Redis集群后,我們最關(guān)心的就是其原有的高可用機(jī)制是否正常。這里,我們可以任意挑選一個(gè)Master的Pod來測試集群的主從切換機(jī)制,如redis-app-0

[root@master redis]# kubectl get pods redis-app-0 -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP            NODE            NOMINATED NODE
redis-app-1   1/1       Running   0          3h        172.17.24.3   192.168.0.144   <none>

進(jìn)入redis-app-0查看:

[root@master redis]# kubectl exec -it redis-app-0 /bin/bash
root@redis-app-0:/data# /usr/local/bin/redis-cli -c
127.0.0.1:6379> role
1) "master"
2) (integer) 13370
3) 1) 1) "172.17.63.9"
      2) "6379"
      3) "13370"
127.0.0.1:6379>

如上可以看到,app-0為master,slave為172.17.63.9redis-app-3。

接著,我們手動(dòng)刪除redis-app-0

[root@master redis]# kubectl delete pod redis-app-0
pod "redis-app-0" deleted
[root@master redis]#  kubectl get pod redis-app-0 -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP            NODE            NOMINATED NODE
redis-app-0   1/1       Running   0          4m        172.17.24.3   192.168.0.144   <none>

我們?cè)龠M(jìn)入redis-app-0內(nèi)部查看:

[root@master redis]# kubectl exec -it redis-app-0 /bin/bash
root@redis-app-0:/data# /usr/local/bin/redis-cli -c
127.0.0.1:6379> role
1) "slave"
2) "172.17.63.9"
3) (integer) 6379
4) "connected"
5) (integer) 13958

如上,redis-app-0變成了slave,從屬于它之前的從節(jié)點(diǎn)172.17.63.9redis-app-3。

六、疑問
至此,大家可能會(huì)疑惑,那為什么沒有使用穩(wěn)定的標(biāo)志,Redis Pod也能正常進(jìn)行故障轉(zhuǎn)移呢?這涉及了Redis本身的機(jī)制。因?yàn)?,Redis集群中每個(gè)節(jié)點(diǎn)都有自己的NodeId(保存在自動(dòng)生成的nodes.conf中),并且該NodeId不會(huì)隨著IP的變化和變化,這其實(shí)也是一種固定的網(wǎng)絡(luò)標(biāo)志。也就是說,就算某個(gè)Redis Pod重啟了,該P(yáng)od依然會(huì)加載保存的NodeId來維持自己的身份。我們可以在NFS上查看redis-app-1的nodes.conf文件:

[root@k8s-node2 ~]# cat /usr/local/k8s/redis/pv1/nodes.conf 96689f2018089173e528d3a71c4ef10af68ee462 192.168.169.209:6379@16379 slave d884c4971de9748f99b10d14678d864187a9e5d3 0 1526460952651 4 connected237d46046d9b75a6822f02523ab894928e2300e6 192.168.169.200:6379@16379 slave c15f378a604ee5b200f06cc23e9371cbc04f4559 0 1526460952651 1 connected
c15f378a604ee5b200f06cc23e9371cbc04f4559 192.168.169.197:6379@16379 master - 0 1526460952651 1 connected 10923-16383d884c4971de9748f99b10d14678d864187a9e5d3 192.168.169.205:6379@16379 master - 0 1526460952651 4 connected 5462-10922c3b4ae23c80ffe31b7b34ef29dd6f8d73beaf85f 192.168.169.198:6379@16379 myself,slave c8a8f70b4c29333de6039c47b2f3453ed11fb5c2 0 1526460952565 3 connected
c8a8f70b4c29333de6039c47b2f3453ed11fb5c2 192.168.169.201:6379@16379 master - 0 1526460952651 6 connected 0-5461vars currentEpoch 6 lastVoteEpoch 4
如上,第一列為NodeId,穩(wěn)定不變;第二列為IP和端口信息,可能會(huì)改變。

這里,我們介紹NodeId的兩種使用場景:

當(dāng)某個(gè)Slave Pod斷線重連后IP改變,但是Master發(fā)現(xiàn)其NodeId依舊, 就認(rèn)為該Slave還是之前的Slave。

當(dāng)某個(gè)Master Pod下線后,集群在其Slave中選舉重新的Master。待舊Master上線后,集群發(fā)現(xiàn)其NodeId依舊,會(huì)讓舊Master變成新Master的slave。

對(duì)于這兩種場景,大家有興趣的話還可以自行測試,注意要觀察Redis的日志。

關(guān)于“如何在K8s上部署Redis集群”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI