從零開始搭建Kubernetes集群(六吐限、在K8S上部署Redis 集群)

一稠项、前言

上一文《從零開始搭建Kubernetes集群(五驾荣、搭建K8S Ingress)》主要介紹了如何在K8S上搭建Ingress轻猖,以及如何通過Ingress訪問后端服務(wù)帆吻。本篇將介紹如何在K8S上部署Redis集群。注意咙边,這里所說的Redis 集群猜煮,指Redis Cluster而非Sentinel模式集群次员。

下圖為Redis集群的架構(gòu)圖,每個(gè)Master都可以擁有多個(gè)Slave王带。當(dāng)Master下線后淑蔚,Redis集群會(huì)從多個(gè)Slave中選舉出一個(gè)新的Master作為替代,而舊Master重新上線后變成新Master的Slave愕撰。


image.png

二刹衫、準(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簡(jiǎn)介

StatefulSet的概念非常重要蝇摸,簡(jiǎn)單來說婶肩,其就是為了解決Pod重啟、遷移后貌夕,Pod的IP律歼、主機(jī)名等網(wǎng)絡(luò)標(biāo)識(shí)會(huì)改變而帶來的問題。IP變化對(duì)于有狀態(tài)的服務(wù)是難以接受的啡专,如在Zookeeper集群的配置文件中险毁,每個(gè)ZK節(jié)點(diǎn)都會(huì)記錄其他節(jié)點(diǎn)的地址信息:

tickTime=2000
dataDir=/home/myname/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=192.168.229.160:2888:3888
server.2=192.168.229.161:2888:3888
server.3=192.168.229.162:2888:3888

但若某個(gè)ZK節(jié)點(diǎn)的Pod重啟后改變了IP,那么就會(huì)導(dǎo)致該節(jié)點(diǎn)脫離集群们童,而如果該配置文件中不使用IP而使用IP對(duì)應(yīng)的域名畔况,則可避免該問題:

server.1=zk-node1:2888:3888
server.2=zk-node2:2888:3888
server.3=zk-node3:2888:3888

也即是說,對(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)求。


image.png

四覆致、部署過程

本文參考項(xiàng)目的README中侄旬,簡(jiǎn)要介紹了基于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

由于硬件資源有限色难,我們可以在k8s-node2上搭建。執(zhí)行如下命令安裝NFS和rpcbind:

yum -y install nfs-utils rpcbind 

其中等缀,NFS依靠遠(yuǎn)程過程調(diào)用(RPC)在客戶端和服務(wù)器端路由請(qǐng)求枷莉,因此需要安裝rpcbind服務(wù)。

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

/usr/local/k8s/redis/pv1 *(rw,all_squash)
/usr/local/k8s/redis/pv2 *(rw,all_squash)
/usr/local/k8s/redis/pv3 *(rw,all_squash)
/usr/local/k8s/redis/pv4 *(rw,all_squash)
/usr/local/k8s/redis/pv5 *(rw,all_squash)
/usr/local/k8s/redis/pv6 *(rw,all_squash)

如上,rw表示讀寫權(quán)限噪裕;all_squash 表示客戶機(jī)上的任何用戶訪問該共享目錄時(shí)都映射成服務(wù)器上的匿名用戶(默認(rèn)為nfsnobody)蹲盘;*表示任意主機(jī)都可以訪問該共享目錄,也可以填寫指定主機(jī)地址州疾,同時(shí)支持正則辜限,如:

/root/share/ 192.168.1.20 (rw,all_squash)
/home/ljm/ *.gdfs.edu.cn (rw,all_squash)

由于我們打算創(chuàng)建一個(gè)6節(jié)點(diǎn)的Redis集群,所以共享了6個(gè)目錄严蓖。當(dāng)然,我們需要在k8s-node2上創(chuàng)建這些路徑氧急,并且為每個(gè)路徑修改權(quán)限:

chmod 777 /usr/local/k8s/redis/pv*

這一步必不可少颗胡,否則掛載時(shí)會(huì)出現(xiàn)mount.nfs: access denied by server while mounting的權(quán)限錯(cuò)誤。

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

systemctl start rpcbind
systemctl start nfs

我們?cè)趉8s-node1上測(cè)試一下毒姨,執(zhí)行:

mount -t nfs 192.168.56.102:/usr/local/k8s/redis/pv1 /mnt

表示將k8s-node2上的共享目錄/usr/local/k8s/redis/pv1映射為k8s-node1的/mnt目錄,我們?cè)?mnt中創(chuàng)建文件:

touch haha

既可以在k8s-node2上看到該文件:

[root@k8s-node2 redis]# ll pv1
總用量 0
-rw-r--r--. 1 nfsnobody nfsnobody 0 5月   2 21:35 haha

可以看到用戶和組為nfsnobody钉寝。

創(chuàng)建PV

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

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

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

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

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

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

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

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

[root@k8s-node1 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如下:

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

查看:

[root@k8s-node1 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如下:

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

查看:

[root@k8s-node1 redis]# kubectl get svc redis-service
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
redis-service   ClusterIP   None         <none>        6379/TCP   53s

可以看到,服務(wù)名稱為redis-service蘸鲸,其CLUSTER-IPNone妖谴,表示這是一個(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文件:

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@k8s-node1 redis]# kubectl get pods -o wide
NAME          READY     STATUS      RESTARTS   AGE       IP                NODE
dns-test      0/1       Completed   0          52m       192.168.169.208   k8s-node2
redis-app-0   1/1       Running     0          1h        192.168.169.207   k8s-node2
redis-app-1   1/1       Running     0          1h        192.168.169.197   k8s-node2
redis-app-2   1/1       Running     0          1h        192.168.169.198   k8s-node2
redis-app-3   1/1       Running     0          1h        192.168.169.205   k8s-node2
redis-app-4   1/1       Running     0          1h        192.168.169.200   k8s-node2
redis-app-5   1/1       Running     0          1h        192.168.169.201   k8s-node2

如上女责,可以看到這些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@k8s-node1 ~]# kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh 
If you don't see a command prompt, try pressing enter.
/ # nslookup redis-app-0.redis-service
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      redis-app-0.redis-service
Address 1: 192.168.169.207 redis-app-0.redis-service.default.svc.cluster.local

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

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

[root@k8s-node1 ~]# 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                            1h
nfs-pv2   200M       RWX            Retain           Bound     default/redis-data-redis-app-3                            1h
nfs-pv3   200M       RWX            Retain           Bound     default/redis-data-redis-app-4                            1h
nfs-pv4   200M       RWX            Retain           Bound     default/redis-data-redis-app-5                            1h
nfs-pv5   200M       RWX            Retain           Bound     default/redis-data-redis-app-0                            1h
nfs-pv6   200M       RWX            Retain           Bound     default/redis-data-redis-app-1                            1h

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 -i --tty ubuntu --image=ubuntu --restart=Never /bin/bash

成功后,我們可以進(jìn)入ubuntu容器中们豌,原項(xiàng)目要求執(zhí)行如下命令安裝基本的軟件環(huán)境:

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

但是涯捻,需要注意的是,在我們天朝望迎,執(zhí)行上述命令前需要提前做一件必要的工作——換源障癌,否則你懂得。我們使用阿里云的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

源修改完畢后涛浙,就可以執(zhí)行上面的兩個(gè)命令。

初始化集群

首先摄欲,我們需要安裝redis-trib

pip install redis-trib

然后轿亮,創(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

如上,命令dig +short redis-app-0.redis-service.default.svc.cluster.local用于將Pod的域名轉(zhuǎn)化為IP胸墙,這是因?yàn)?code>redis-trib不支持域名來創(chuàng)建集群。

其次,為每個(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@k8s-node1 ~]# 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
c15f378a604ee5b200f06cc23e9371cbc04f4559 192.168.169.197:6379@16379 master - 0 1526454835084 1 connected 10923-16383
96689f2018089173e528d3a71c4ef10af68ee462 192.168.169.204:6379@16379 slave d884c4971de9748f99b10d14678d864187a9e5d3 0 1526454836491 4 connected
d884c4971de9748f99b10d14678d864187a9e5d3 192.168.169.199:6379@16379 master - 0 1526454835487 4 connected 5462-10922
c3b4ae23c80ffe31b7b34ef29dd6f8d73beaf85f 192.168.169.198:6379@16379 myself,master - 0 1526454835000 3 connected 0-5461
c8a8f70b4c29333de6039c47b2f3453ed11fb5c2 192.168.169.201:6379@16379 slave c3b4ae23c80ffe31b7b34ef29dd6f8d73beaf85f 0 1526454836000 3 connected
237d46046d9b75a6822f02523ab894928e2300e6 192.168.169.200:6379@16379 slave c15f378a604ee5b200f06cc23e9371cbc04f4559 0 1526454835000 1 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:4
...省略...

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

[root@k8s-node2 ~]# ll /usr/local/k8s/redis/pv3/
總用量 8
-rw-r--r--. 1 nfsnobody nfsnobody   0 5月  16 15:07 appendonly.aof
-rw-r--r--. 1 nfsnobody nfsnobody 175 5月  16 15:07 dump.rdb
-rw-r--r--. 1 nfsnobody nfsnobody 817 5月  16 16:55 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ù)載均:

piVersion: 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@k8s-node1 redis]# kubectl get svc redis-access-service -o wide
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE       SELECTOR
redis-access-service   ClusterIP   10.105.11.209   <none>        6379/TCP   41m       app=redis,appCluster=redis-cluster

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

五、測(cè)試主從切換

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

[root@k8s-node1 redis]# kubectl get pods redis-app-2 -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP                NODE
redis-app-2   1/1       Running   0          2h        192.168.169.198   k8s-node2

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

[root@k8s-node1 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> role
1) "master"
2) (integer) 8666
3) 1) 1) "192.168.169.201"
      2) "6379"
      3) "8666"
127.0.0.1:6379>

如上可以看到别凤,其為master,slave為192.168.169.201即redis-app-5`领虹。

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

[root@k8s-node1 redis]# kubectl delete pods redis-app-2
pod "redis-app-2" deleted

[root@k8s-node1 redis]# kubectl get pods redis-app-2 -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP                NODE
redis-app-2   1/1       Running   0          20s       192.168.169.210   k8s-node2

如上,IP改變?yōu)?code>192.168.169.210塌衰。我們?cè)龠M(jìn)入redis-app-2內(nèi)部查看:

[root@k8s-node1 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> role
1) "slave"
2) "192.168.169.201"
3) (integer) 6379
4) "connected"
5) (integer) 8960
127.0.0.1:6379>

如上诉稍,redis-app-2變成了slave,從屬于它之前的從節(jié)點(diǎn)192.168.169.201redis-app-5最疆。

六杯巨、疑問

至此,大家可能會(huì)疑惑努酸,前面講了這么多似乎并沒有體現(xiàn)出StatefulSet的作用服爷,其提供的穩(wěn)定標(biāo)志redis-app-*僅在初始化集群的時(shí)候用到,而后續(xù)Redis Pod的通信或配置文件中并沒有使用該標(biāo)志蚊逢。我想說层扶,是的,本文使用StatefulSet部署Redis確實(shí)沒有體現(xiàn)出其優(yōu)勢(shì)烙荷,還不如介紹Zookeeper集群來的明顯镜会,不過沒關(guān)系,學(xué)到知識(shí)就好终抽。

那為什么沒有使用穩(wěn)定的標(biāo)志戳表,Redis Pod也能正常進(jìn)行故障轉(zhuǎn)移呢桶至?這涉及了Redis本身的機(jī)制。因?yàn)樨倚瘢琑edis集群中每個(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-1nodes.conf文件:

[root@k8s-node2 ~]# cat /usr/local/k8s/redis/pv1/nodes.conf 
96689f2018089173e528d3a71c4ef10af68ee462 192.168.169.209:6379@16379 slave d884c4971de9748f99b10d14678d864187a9e5d3 0 1526460952651 4 connected
237d46046d9b75a6822f02523ab894928e2300e6 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-16383
d884c4971de9748f99b10d14678d864187a9e5d3 192.168.169.205:6379@16379 master - 0 1526460952651 4 connected 5462-10922
c3b4ae23c80ffe31b7b34ef29dd6f8d73beaf85f 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-5461
vars currentEpoch 6 lastVoteEpoch 4

如上伪窖,第一列為NodeId,穩(wěn)定不變居兆;第二列為IP和端口信息覆山,可能會(huì)改變。

這里泥栖,我們介紹NodeId的兩種使用場(chǎng)景:

  • 當(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ì)于這兩種場(chǎng)景甸陌,大家有興趣的話還可以自行測(cè)試须揣,注意要觀察Redis的日志。

七钱豁、廢話

至此耻卡,我們的Redis集群就搭建完畢了。如果大家有興趣牲尺,可以嘗試使用Service配合Deployment方式來部署Redis集群卵酪,該方式相對(duì)來說更容易理解。下一章節(jié)《從零開始搭建Kubernetes集群(七谤碳、如何監(jiān)控K8S集群的日志)》溃卡,敬請(qǐng)期待。

本人水平有限蜒简,難免有錯(cuò)誤或遺漏之處瘸羡,望大家指正和諒解,歡迎評(píng)論留言搓茬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末犹赖,一起剝皮案震驚了整個(gè)濱河市队他,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌峻村,老刑警劉巖麸折,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異粘昨,居然都是意外死亡垢啼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門雾棺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膊夹,“玉大人,你說我怎么就攤上這事捌浩。” “怎么了工秩?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵尸饺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我助币,道長(zhǎng)浪听,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任眉菱,我火速辦了婚禮迹栓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俭缓。我一直安慰自己克伊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布华坦。 她就那樣靜靜地躺著愿吹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪惜姐。 梳的紋絲不亂的頭發(fā)上犁跪,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音蝶棋,去河邊找鬼铺然。 笑死馍佑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枫耳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼逞刷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼嘉涌!你這毒婦竟也來了妻熊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仑最,失蹤者是張志新(化名)和其女友劉穎扔役,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體警医,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亿胸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了预皇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侈玄。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吟温,靈堂內(nèi)的尸體忽然破棺而出序仙,到底是詐尸還是另有隱情,我是刑警寧澤鲁豪,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布潘悼,位于F島的核電站,受9級(jí)特大地震影響爬橡,放射性物質(zhì)發(fā)生泄漏治唤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一糙申、第九天 我趴在偏房一處隱蔽的房頂上張望宾添。 院中可真熱鬧,春花似錦柜裸、人聲如沸缕陕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)榄檬。三九已至,卻和暖如春衔统,著一層夾襖步出監(jiān)牢的瞬間鹿榜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工锦爵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舱殿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓险掀,卻偏偏與公主長(zhǎng)得像沪袭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子樟氢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容