2) Redis Operator for Redis Cluster (by opstree) - jangjaelee/tutorials-redis-operator GitHub Wiki


2022.06. ์ด์žฅ์žฌ ๐Ÿ“ง [email protected] ๐Ÿ“‚ https://github.com/jangjaelee ๐Ÿ“’ http://www.awx.kr


 

Introduction

Opstree Solutions์—์„œ ์ œ์ž‘ํ•œ Redis Operator๋Š” Kubernetes cluster์—์„œ Redis Standalone/Cluster mode ์„ค์ •์„ ๋งŒ๋“ค๊ณ  ๊ฐ๋…ํ•˜๋Š” Open Source๋ฅผ ์ง€์›ํ•˜๋Š” Redis Community๋ฅผ ์œ„ํ•œ Golang-based Redis Operator ์ž…๋‹ˆ๋‹ค.

Cloud ๋ฐ Bare-metal ํ™˜๊ฒฝ์—์„œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Redis Cluster ์„ค์ •์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, redis-exporter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด์žฅ๋œ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ง€์›ํ•˜๋Š” Redis ์„ค์ • ์œ ํ˜•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Redis Standalone
  • Redis Cluster (in-build leader follower with sharding and replication mode)

 

Supported Features

Redis Operator๊ฐ€ ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • Redis Cluster (sharding ๋ฐ replication mode์˜ leader-follower) ๋ฐ Standalone ์„ค์ •
  • Redis Exporter๋ฅผ ์‚ฌ์šฉํ•œ ๋‚ด์žฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์ง€์›์œผ๋กœ ์ž์„ธํ•œ ํ†ต์ฐฐ๋ ฅ ์ œ๊ณต
  • PVC Template์„ ์‚ฌ์šฉํ•œ ๋™์  ์Šคํ† ๋ฆฌ์ง€ ํ”„๋กœ๋น„์ €๋‹
  • Redis ๊ตฌ์„ฑ์˜ ์„ฑ๋Šฅ ์กฐ์ • ๋ชจ๋ฒ” ์‚ฌ๋ก€
  • Cluster ๋ฐ Standalone ์„ค์ •์— ๋Œ€ํ•œ ์•”ํ˜ธ ๋ฐ ์•”ํ˜ธ ์—†๋Š” ์ง€์›
  • ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ Kubernetes ๊ธฐ๋ฐ˜ object ์ง€์›
    • NodeSelector
    • Affinity
    • Resource and Limits
    • Tolerations
    • SecutiryContext
    • Storage

 

Architecture

Redis-Operator_opstree.png

Redis-Operator_architecture_opstree-01.png

 

Prerequisites

โœ…  Prometheus Operator ์„ค์น˜์™€ ์†Œ๊ฐœ๋Š” ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

Prometheus Operator for Beginner

โœ… MetalLB ์„ค์น˜์™€ ์†Œ๊ฐœ๋Š” ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

MetalLB

 

Step 1. Installation Redis Operator

Redis Operator ์„ค์น˜๋Š” YAML manifest์™€ Helm chart๋ฅผ ์ด์šฉํ•œ ๋‘ ๊ฐ€์ง€ ์„ค์น˜ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ํŽธํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ Redis Operator๋ฅผ ์„ค์น˜ํ•˜์„ธ์š”.

Redis์™€ redis-exporter์˜ ๊ธฐ๋ณธ ๋ฒ„์ „์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Redis v6.2.5 (default)
  • redis-exporter v1.0 (default)

Step 1.1. using YAML manifest

์ œ๊ณต๋˜๋Š” YAML manifest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Redis Operator๋ฅผ ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ž…๋‹ˆ๋‹ค.

manager.yaml์— namespace ์ƒ์„ฑ์„ ์œ„ํ•œ manifest ๋‚ด์šฉ์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด redis-operator namespace๊ฐ€ ํ•จ๊ป˜ ์ƒ์„ฑ ๋ฉ๋‹ˆ๋‹ค.

$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/master/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml
$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/master/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml
$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/master/config/rbac/serviceaccount.yaml
$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/master/config/rbac/role.yaml
$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/master/config/rbac/role_binding.yaml
$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/master/config/manager/manager.yaml

Step 1.2. using Helm chart

Redis Operator๋ฅผ ์ข€๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Helm chart๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ values.yaml ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜๋Š” helm show ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ values๋ฅผ ํŒŒ์ผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ helm show values ot-helm/redis-operator > values.yaml

Redis Operator Helm chart ์ €์žฅ์†Œ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

$ helm repo add ot-helm https://ot-container-kit.github.io/helm-charts/
$ helm repo update
$ helm install redis-operator ot-helm/redis-operator -n redis-operator --create-namespace

Step 1.3. See installed objects

์ด์ œ operator ์„ค์น˜๋ฅผ ์™„๋ฃŒ ํ•˜์˜€์œผ๋‹ˆ ์ƒ์„ฑ๋œ objects๊ณผ ๊ตฌ๋™์ค‘์ธ pod๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

$ kubectl get all -n redis-operator
NAME                                  READY   STATUS    RESTARTS      AGE
pod/redis-operator-78c6c95b78-wzkrb   1/1     Running   1             50s

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/redis-operator   1/1     1            1           1m

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/redis-operator-78c6c95b78   1         1         1       1m

์ƒ์„ฑ๋œ CRD๋„ ํ•จ๊ป˜ ํ™•์ธํ•˜๋ฉด redis์™€ redisclusters CRD๋“ค์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

redis CRD๋Š” Redis Standalone ์„ค์ • ์œ ํ˜•์„ ์œ„ํ•จ์ด๋ฉฐ, redisclusters CRD๋Š” Redis Cluster ์„ค์ • ์œ ํ˜•์„ ์œ„ํ•œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

$ kubectl api-resources | egrep '^NAME|redis'
NAME                              SHORTNAMES         APIVERSION                             NAMESPACED   KIND
redis                                                redis.redis.opstreelabs.in/v1beta1     true         Redis
redisclusters                                        redis.redis.opstreelabs.in/v1beta1     true         RedisCluster

kubectl plugin manager์ธ Krew์˜ get-all plugins์„ ์„ค์น˜ํ•˜๋ฉด ์ข€๋” ์‰ฝ๊ฒŒ ์ƒ์„ฑ๋œ objects๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”—  https://github.com/corneliusweig/ketall

$ kubectl get-all -n redis-operator
NAME                                                     NAMESPACE       AGE
configmap/6cab913b.redis.opstreelabs.in                  redis-operator  9s
configmap/kube-root-ca.crt                               redis-operator  18s
pod/redis-operator-78c6c95b78-wzkrb                      redis-operator  18s
secret/default-token-gjvhs                               redis-operator  18s
secret/redis-operator-token-6n5hd                        redis-operator  18s
secret/sh.helm.release.v1.redis-operator.v1              redis-operator  18s
serviceaccount/default                                   redis-operator  18s
serviceaccount/redis-operator                            redis-operator  18s
deployment.apps/redis-operator                           redis-operator  18s
replicaset.apps/redis-operator-78c6c95b78                redis-operator  18s
lease.coordination.k8s.io/6cab913b.redis.opstreelabs.in  redis-operator  9s

 

Step 2. Deploy Redis and Configuration

์ด๋ฒˆ ๋‹จ๊ณ„์—์„œ๋Š” Redis๋ฅผ ๋ฐฐํฌํ•˜๊ณ  CR์˜ ๊ตฌ์„ฑ์„ ํ•œ๋ฒˆ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์„ค์น˜์— ์•ž์„œ Redis ๋‚ด์—์„œ password ๊ธฐ๋ฐ˜ ์ธ์ฆ์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ secret์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, secret์˜ ๊ธฐ๋ณธ ์ด๋ฆ„์€ redis-secret ์ด๋ฉฐ, key ์ด๋ฆ„์€ password ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  helm chart๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด override๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

redis auth๋ฅผ ์œ„ํ•œ secret object๋ฅผ ์ƒ์„ฑ ํ•ฉ๋‹ˆ๋‹ค.

$ kubectl create secret generic redis-secret --from-literal=password=redispassword -n redis-system
secret/redis-secret created

$ kubectl describe secret/redis-secret -n redis-system
Name:         redis-secret
Namespace:    redis-system
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  13 bytes

Step 2.1. Redis Standalone

Redis Standalone mode์—์„œ๋Š” Redis๋ฅผ ๋‹จ์ผ Pod๋กœ ๋ฐฐํฌํ•˜๋ฏ€๋กœ StatefulSets์˜ replicas: 1 ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์„ค์ •์ด ๊ฐ„ํŽธํ•˜๊ณ  ๋ณต์žก์„ฑ์ด ์—†์ง€๋งŒ, ๊ณ ๊ฐ€์šฉ์„ฑ(HA) ๋ฐ ๋ณต์›๋ ฅ(resilience)์€ ์ œ๊ณต๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Redis_Standalone.png

๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ Redis๋ฅผ Standalone mode๋กœ ๋ฐฐํฌ ํ•ฉ๋‹ˆ๋‹ค.

Prometheus Operator์˜ ServiceMonitor CR์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด --set serviceMonitor.enabled=true value๋ฅผ ์‚ฌ์šฉํ•˜์˜€์œผ๋ฉฐ Prometheus Operator๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•ด๋‹น value๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”—  Redis Standalone์˜ Helm chart ๋‚ด์šฉ์€ [๋งํฌ]์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

$ helm install redis-standalone ot-helm/redis \
-n redis-system --create-system \
--set redisCluster.redisSecret.secretName="redis-secret" \
--set redisCluster.redisSecret.secretKey="password" \
--set serviceMonitor.enabled=true \
--set serviceMonitor.namespace="redis-system"

๋ฐฐํฌ๋œ objects๋ฅผ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

$ kubectl get-all -n redis-system
NAME                                                                         NAMESPACE     AGE
configmap/kube-root-ca.crt                                                   redis-system  1m
endpoints/redis-standalone                                                   redis-system  1m
endpoints/redis-standalone-headless                                          redis-system  1m
persistentvolumeclaim/redis-standalone-redis-standalone-0                    redis-system  1m
pod/redis-standalone-0                                                       redis-system  1m
secret/default-token-kbmwd                                                   redis-system  1m
secret/redis-secret                                                          redis-system  1m
secret/sh.helm.release.v1.redis-standalone.v1                                redis-system  1m
secret/sh.helm.release.v1.redis-standalone.v2                                redis-system  1m
serviceaccount/default                                                       redis-system  1m
service/redis-standalone                                                     redis-system  1m
service/redis-standalone-headless                                            redis-system  1m
controllerrevision.apps/redis-standalone-7fbb5dd9fc                          redis-system  1m
statefulset.apps/redis-standalone                                            redis-system  1m
endpointslice.discovery.k8s.io/redis-standalone-hccd9                        redis-system  1m
endpointslice.discovery.k8s.io/redis-standalone-headless-rvxhs               redis-system  1m
servicemonitor.monitoring.coreos.com/redis-standalone-prometheus-monitoring  redis-system  1m
redis.redis.redis.opstreelabs.in/redis-standalone                            redis-system  1m

Redis Operator Controller๋Š” redis CR์˜ ์ƒ์„ฑ์„ ๊ฐ์ง€ํ•˜์—ฌ StatefulSet object๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Redis Standalone์„ ๊ตฌ์„ฑํ•˜๋Š” redis CR์˜ configuration์€ ๋‹ค์Œ์˜ ๋งํฌ์—์„œ Helm Parameters๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”— https://ot-container-kit.github.io/redis-operator/guide/redis-config.html

Step 2.2. Redis Cluster

Redis Cluster๋Š” ๋ฐ์ดํ„ฐ ์ƒค๋”ฉ ์ „๋žต์œผ๋กœ ์—ฌ๋Ÿฌ Redis node์— ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋ถ„ํ• ํ•ด์ค๋‹ˆ๋‹ค. ๋ถ„์‚ฐ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ๋‹จ์ผ ์žฅ์•  ์ง€์ (SPOF) ๋ฐฉ์ง€ํ•˜๋Š” Redis์˜ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ ์ž…๋‹ˆ๋‹ค.

Redis_Cluster.png

๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ Redis๋ฅผ Cluster mode๋กœ ๋ฐฐํฌ ํ•ฉ๋‹ˆ๋‹ค.

Prometheus Operator์˜ ServiceMonitor CR์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด --set serviceMonitor.enabled=true value๋ฅผ ์‚ฌ์šฉํ•˜์˜€์œผ๋ฉฐ Prometheus Operator๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•ด๋‹น value๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”—  Redis Cluster์˜ Helm chart ๋‚ด์šฉ์€ [๋งํฌ]์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

$ helm install redis-cluster ot-helm/redis-cluster \
-n redis-system --create-system \
--set redisCluster.clusterSize=3 \
--set redisCluster.leader.replicas=3 \
--set redisCluster.follower.replicas=3 \
--set redisCluster.redisSecret.secretName="redis-secret" \
--set redisCluster.redisSecret.secretKey="password" \
--set serviceMonitor.enabled=true \
--set serviceMonitor.namespace="redis-system"

์ด์ œ ๋ฐฐํฌ๋œ objects๋ฅผ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

$ kubectl get all -n redis-system
NAME                           READY   STATUS    RESTARTS   AGE
pod/redis-cluster-follower-0   2/2     Running   0          4m4s
pod/redis-cluster-follower-1   2/2     Running   0          3m46s
pod/redis-cluster-follower-2   2/2     Running   0          3m13s
pod/redis-cluster-leader-0     2/2     Running   0          3m10s
pod/redis-cluster-leader-1     2/2     Running   0          2m46s
pod/redis-cluster-leader-2     2/2     Running   0          2m11s

NAME                                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
service/redis-cluster-follower            ClusterIP   10.103.232.239   <none>        6379/TCP,9121/TCP   4m4s
service/redis-cluster-follower-headless   ClusterIP   None             <none>        6379/TCP            4m4s
service/redis-cluster-leader              ClusterIP   10.101.133.245   <none>        6379/TCP,9121/TCP   3m10s
service/redis-cluster-leader-headless     ClusterIP   None             <none>        6379/TCP            3m10s

NAME                                      READY   AGE
statefulset.apps/redis-cluster-follower   3/3     4m
statefulset.apps/redis-cluster-leader     3/3     4m
$ kubectl get rediscluster -n redis-system
NAME            CLUSTERSIZE   LEADERREPLICAS   FOLLOWERREPLICAS   AGE
redis-cluster   3             3                3                  1m
$ kubectl get-all -n redis-system
NAME                                                                               NAMESPACE     AGE
configmap/kube-root-ca.crt                                                         redis-system  14h
endpoints/redis-cluster-follower                                                   redis-system  88m
endpoints/redis-cluster-follower-headless                                          redis-system  88m
endpoints/redis-cluster-leader                                                     redis-system  88m
endpoints/redis-cluster-leader-headless                                            redis-system  88m
persistentvolumeclaim/redis-cluster-follower-redis-cluster-follower-0              redis-system  88m
persistentvolumeclaim/redis-cluster-follower-redis-cluster-follower-1              redis-system  88m
persistentvolumeclaim/redis-cluster-follower-redis-cluster-follower-2              redis-system  88m
persistentvolumeclaim/redis-cluster-leader-redis-cluster-leader-0                  redis-system  88m
persistentvolumeclaim/redis-cluster-leader-redis-cluster-leader-1                  redis-system  88m
persistentvolumeclaim/redis-cluster-leader-redis-cluster-leader-2                  redis-system  88m
pod/redis-cluster-follower-0                                                       redis-system  88m
pod/redis-cluster-follower-1                                                       redis-system  88m
pod/redis-cluster-follower-2                                                       redis-system  87m
pod/redis-cluster-leader-0                                                         redis-system  88m
pod/redis-cluster-leader-1                                                         redis-system  87m
pod/redis-cluster-leader-2                                                         redis-system  87m
secret/default-token-kbmwd                                                         redis-system  14h
secret/redis-secret                                                                redis-system  14h
secret/sh.helm.release.v1.redis-cluster.v1                                         redis-system  91m
serviceaccount/default                                                             redis-system  14h
service/redis-cluster-follower                                                     redis-system  88m
service/redis-cluster-follower-headless                                            redis-system  88m
service/redis-cluster-leader                                                       redis-system  88m
service/redis-cluster-leader-headless                                              redis-system  88m
controllerrevision.apps/redis-cluster-follower-5444b5bdcf                          redis-system  88m
controllerrevision.apps/redis-cluster-leader-5699997689                            redis-system  88m
statefulset.apps/redis-cluster-follower                                            redis-system  88m
statefulset.apps/redis-cluster-leader                                              redis-system  88m
endpointslice.discovery.k8s.io/redis-cluster-follower-b4vsl                        redis-system  88m
endpointslice.discovery.k8s.io/redis-cluster-follower-headless-l46zg               redis-system  88m
endpointslice.discovery.k8s.io/redis-cluster-leader-headless-dtskw                 redis-system  88m
endpointslice.discovery.k8s.io/redis-cluster-leader-xb2cd                          redis-system  88m
servicemonitor.monitoring.coreos.com/redis-cluster-follower-prometheus-monitoring  redis-system  88m
servicemonitor.monitoring.coreos.com/redis-cluster-leader-prometheus-monitoring    redis-system  88m
rediscluster.redis.redis.opstreelabs.in/redis-cluster                              redis-system  88m

Redis Standalone์™€๋Š” ๋‹ค๋ฅด๊ฒŒ Redis Cluster mode์—์„œ๋Š” rediscluster CR์ด ์ƒ์„ฑ๋˜๋ฉด Leader์™€ Follow๋ฅผ ์œ„ํ•œ StatefulSet์ด ๊ฐ๊ฐ ๋ฐฐํฌ ๋œ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ์— ๋”ฐ๋ผ Service์™€ Prometheus Operator์˜ ServiceMonitor๋„ ํ•จ๊ป˜ ์ƒ์„ฑ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Redis leader pod์— ์—ฐ๊ฒฐํ•˜์—ฌ redis cluster ์ •๋ณด์™€ node ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

$ kubectl exec -it redis-cluster-leader-0 -n redis-system -- redis-cli -a redispassword cluster info
Defaulted container "redis-cluster-leader" out of: redis-cluster-leader, redis-exporter
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
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:376
cluster_stats_messages_pong_sent:375
cluster_stats_messages_sent:751
cluster_stats_messages_ping_received:372
cluster_stats_messages_pong_received:376
cluster_stats_messages_meet_received:3
cluster_stats_messages_received:751
$ kubectl exec -it redis-cluster-leader-0 -n redis-system -- redis-cli -a redispassword cluster nodes
Defaulted container "redis-cluster-leader" out of: redis-cluster-leader, redis-exporter
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
5483f9be46324b9e8f48b431fc4128c788525cdc 172.16.10.103:6379@16379 master - 0 1655908354065 2 connected 5461-10922
4d0bd6e99c00cddd6f9858da371526f39fef157a 172.16.10.75:6379@16379 slave 5483f9be46324b9e8f48b431fc4128c788525cdc 0 1655908352043 2 connected
87fe6e67e43ddb9f9ad6acd830d360b83250c630 172.16.84.121:6379@16379 slave 7ded434ed7be8db05a7851dc44e082e38bbf398b 0 1655908353559 1 connected
a956b4aaf4a04957bc6b0a42bdb62122c91fb44e 172.16.84.115:6379@16379 slave 742149aba5d2e572b6f85ea59a964880fa79b367 0 1655908352545 3 connected
7ded434ed7be8db05a7851dc44e082e38bbf398b 172.16.84.122:6379@16379 myself,master - 0 1655908351000 1 connected 0-5460
742149aba5d2e572b6f85ea59a964880fa79b367 172.16.78.67:6379@16379 master - 0 1655908352547 3 connected 10923-16383

redis cluster nodes ์ƒํƒœ์—์„œ IP ์ •๋ณด์™€ Redis instance์˜ pod IP๋ฅผ ๋Œ€์กฐํ•˜๋ฉด ์–ด๋–ค leader์™€ follower๊ฐ€ ๊ฐ๊ฐ ์–ด๋–ค pod๋ผ๋ฆฌ master-replica๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ kubectl get pod -n redis-system -o wide
NAME                       READY   STATUS    RESTARTS   AGE     IP              NODE            NOMINATED NODE   READINESS GATES
redis-cluster-follower-0   2/2     Running   0          6m1s    172.16.84.121   k8s-w3-dragon   <none>           <none>
redis-cluster-follower-1   2/2     Running   0          7m38s   172.16.10.75    k8s-w2-dragon   <none>           <none>
redis-cluster-follower-2   2/2     Running   0          7m5s    172.16.84.115   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-0     2/2     Running   0          6m16s   172.16.84.122   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-1     2/2     Running   0          7m53s   172.16.10.103   k8s-w2-dragon   <none>           <none>
redis-cluster-leader-2     2/2     Running   0          7m20s   172.16.78.67    k8s-w1-dragon   <none>           <none>

๊ทธ๋ฆฌ๊ณ  pod์˜ log๋ฅผ ์ฐ์–ด๋ณด๋ฉด master-replica์˜ replication ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# Redis leader-0 node (master-0) 

$ kubectl logs -f pod/redis-cluster-leader-0 -n redis-system -c redis-cluster-leader
Starting redis service in cluster mode.....
11:C 22 Jun 2022 14:27:20.230 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
11:C 22 Jun 2022 14:27:20.230 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=11, just started
11:C 22 Jun 2022 14:27:20.230 # Configuration loaded
11:M 22 Jun 2022 14:27:20.230 * monotonic clock: POSIX clock_gettime
11:M 22 Jun 2022 14:27:20.231 * Node configuration loaded, I'm 7ded434ed7be8db05a7851dc44e082e38bbf398b
11:M 22 Jun 2022 14:27:20.231 * Running mode=cluster, port=6379.
11:M 22 Jun 2022 14:27:20.231 # Server initialized
11:M 22 Jun 2022 14:27:20.231 * Ready to accept connections
11:M 22 Jun 2022 14:28:40.238 # configEpoch set to 1 via CLUSTER SET-CONFIG-EPOCH
11:M 22 Jun 2022 14:28:45.207 # Cluster state changed: ok
11:M 22 Jun 2022 14:28:57.589 * Replica 172.16.84.121:6379 asks for synchronization
11:M 22 Jun 2022 14:28:57.589 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '8e3ffd79b9f7370b05effda9a837c2956e5fabed', my replication IDs are 'd8bea88fcebd4c90442116e74a15a7fd2a3935d4' and '0000000000000000000000000000000000000000')
11:M 22 Jun 2022 14:28:57.589 * Replication backlog created, my new replication IDs are '8e2dab8037c5e9c194cf0c659c9c28f77c08614e' and '0000000000000000000000000000000000000000'
11:M 22 Jun 2022 14:28:57.589 * Starting BGSAVE for SYNC with target: disk
11:M 22 Jun 2022 14:28:57.589 * Background saving started by pid 109
109:C 22 Jun 2022 14:28:57.591 * DB saved on disk
109:C 22 Jun 2022 14:28:57.591 * RDB: 0 MB of memory used by copy-on-write
11:M 22 Jun 2022 14:28:57.619 * Background saving terminated with success
11:M 22 Jun 2022 14:28:57.619 * Synchronization with replica 172.16.84.121:6379 succeeded
# Redis follower-0 node (replica-0)

$ kubectl logs -f pod/redis-cluster-follower-0 -n redis-system -c redis-cluster-follower
Starting redis service in cluster mode.....
13:C 22 Jun 2022 14:27:35.559 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
13:C 22 Jun 2022 14:27:35.559 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=13, just started
13:C 22 Jun 2022 14:27:35.559 # Configuration loaded
13:M 22 Jun 2022 14:27:35.560 * monotonic clock: POSIX clock_gettime
13:M 22 Jun 2022 14:27:35.560 * Node configuration loaded, I'm 87fe6e67e43ddb9f9ad6acd830d360b83250c630
13:M 22 Jun 2022 14:27:35.561 * Running mode=cluster, port=6379.
13:M 22 Jun 2022 14:27:35.561 # Server initialized
13:M 22 Jun 2022 14:27:35.561 * Ready to accept connections
13:S 22 Jun 2022 14:28:57.588 * Before turning into a replica, using my own master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
13:S 22 Jun 2022 14:28:57.588 * Connecting to MASTER 172.16.84.122:6379
13:S 22 Jun 2022 14:28:57.588 * MASTER <-> REPLICA sync started
13:S 22 Jun 2022 14:28:57.588 # Cluster state changed: ok
13:S 22 Jun 2022 14:28:57.588 * Non blocking connect for SYNC fired the event.
13:S 22 Jun 2022 14:28:57.589 * Master replied to PING, replication can continue...
13:S 22 Jun 2022 14:28:57.589 * Trying a partial resynchronization (request 8e3ffd79b9f7370b05effda9a837c2956e5fabed:1).
13:S 22 Jun 2022 14:28:57.590 * Full resync from master: 8e2dab8037c5e9c194cf0c659c9c28f77c08614e:0
13:S 22 Jun 2022 14:28:57.590 * Discarding previously cached master state.
13:S 22 Jun 2022 14:28:57.619 * MASTER <-> REPLICA sync: receiving 175 bytes from master to disk
13:S 22 Jun 2022 14:28:57.619 * MASTER <-> REPLICA sync: Flushing old data
13:S 22 Jun 2022 14:28:57.619 * MASTER <-> REPLICA sync: Loading DB in memory
13:S 22 Jun 2022 14:28:57.620 * Loading RDB produced by version 6.2.5
13:S 22 Jun 2022 14:28:57.620 * RDB age 0 seconds
13:S 22 Jun 2022 14:28:57.620 * RDB memory usage when created 2.60 Mb
13:S 22 Jun 2022 14:28:57.620 * MASTER <-> REPLICA sync: Finished with success
13:S 22 Jun 2022 14:28:57.621 * Background append only file rewriting started by pid 83
13:S 22 Jun 2022 14:28:57.650 * AOF rewrite child asks to stop sending diffs.
83:C 22 Jun 2022 14:28:57.650 * Parent agreed to stop sending diffs. Finalizing AOF...
83:C 22 Jun 2022 14:28:57.650 * Concatenating 0.00 MB of AOF diff received from parent.
83:C 22 Jun 2022 14:28:57.651 * SYNC append only file rewrite performed
83:C 22 Jun 2022 14:28:57.651 * AOF rewrite: 0 MB of memory used by copy-on-write
13:S 22 Jun 2022 14:28:57.725 * Background AOF rewrite terminated with success
13:S 22 Jun 2022 14:28:57.725 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
13:S 22 Jun 2022 14:28:57.725 * Background AOF rewrite finished successfully

Redis Cluster์„ ๊ตฌ์„ฑํ•˜๋Š” rediscluster CR์˜ configuration์€ ๋‹ค์Œ์˜ ๋งํฌ์—์„œ Helm Parameters๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”—  https://ot-container-kit.github.io/redis-operator/guide/redis-cluster-config.html

Step 2.3. Exposing Service (External Endpoint)

Redis Operator๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Redis Standalone์™€ Cluster ๋ชจ๋‘ Service Endpoint๋Š” Kubernetes cluster๋‚ด๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Service object์˜ Type์„ NodePort ๋˜๋Š” LoadBalancer ์œ ํ˜•์œผ๋กœ ์„œ๋น„์Šค๋ฅผ ์™ธ๋ถ€๋…ธ์ถœ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Redis Standalone์™€ Cluster๋Š” Helm chart์— external Service๋ฅผ ์œ„ํ•œ ๊ตฌ์„ฑ ์„ค์ •์„ helm value๋ฅผ ํ†ตํ•ด ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด Redis๋ฅผ Kubernetes cluster ์™ธ๋ถ€๋กœ ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

externalService:
  enabled: true
  annotations:
    metallb.universe.tf/address-pool: "default"
  serviceType: LoadBalancer
  port: 6379

๋˜๋Š”, helm ๋ช…๋ น์–ด์˜ set value๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CLI์—์„œ๋„ ๊ตฌ์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Redis Cluster์˜ Redis๋ฅผ ์™ธ๋ถ€๋…ธ์ถœ ์‹œ์ผœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

$ helm upgrade redis-cluster ot-helm/redis-cluster \
-n redis-system --install \
--set redisCluster.clusterSize=3 \
--set redisCluster.leader.replicas=3 \
--set redisCluster.follower.replicas=3 \
--set redisCluster.redisSecret.secretName="redis-secret" \
--set redisCluster.redisSecret.secretKey="password" \
--set serviceMonitor.enabled=true \
--set serviceMonitor.namespace="redis-system" \
--set externalService.enabled=true \
--set externalService.annotation."metallb\.universe\.tf/address-pool"="default"

externalService.annotation์—๋Š” external LoadBalancer๋ฅผ ๋ช…์‹œํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” LoadBalancer๋ฅผ ํ™•์ธํ›„ ์ ์ ˆํ•˜๊ฒŒ ๊ธฐ์žฌํ•˜์—ฌ ์‚ฌ์šฉํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ํ•„์ž๋Š” MetalLB๋ฅผ ์‚ฌ์šฉ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

service object ์ด๋ฆ„์€ StatefulSets ์ด๋ฆ„์„ prefix๋กœ ์‚ฌ์šฉํ•˜์—ฌ <statefulset name>-external-service ์™€ ๊ฐ™์ด ์ƒ์„ฑ ๋ฉ๋‹ˆ๋‹ค.

$ kubectl get svc -n redis-system | egrep '^NAME|external-service'
NAME                                      TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)             AGE
redis-cluster-follower-external-service   LoadBalancer   10.105.17.6     192.168.1.184   6379:32311/TCP      19m
redis-cluster-leader-external-service     LoadBalancer   10.96.173.154   192.168.1.185   6379:32114/TCP      19m

external Service๋ฅผ ์ƒ์„ฑํ•˜๊ณ  redis-cli๋กœ ์„œ๋ฒ„์— ์ ‘์†ํ•˜๋ฉด ์ ‘์†์ด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

$ redis-cli -h 192.168.1.184 -a redispassword cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.

Could not connect to Redis at 192.168.1.184:6379: No route to host

$ redis-cli -h 192.168.1.185 -a redispassword cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.

Could not connect to Redis at 192.168.1.185:6379: No route to host

์ด์œ ๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ service object์— ๋ช…์‹œ๋œ Label selector์—์„œ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌ ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ™•์ธ์„ ํ•ด๋ณด๋ฉด redis-cluster-leader-external-service์™€ redis-cluster-follow-external-service์˜ Label selector์— redis_setup_type์˜ ๊ฐ’์ด ๊ฐ๊ฐ leader์™€ follower๋กœ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

$ kubectl get svc/redis-cluster-leader-external-service -n redis-system -o=jsonpath='{.spec.selector}' | jq
{
  "app": "redis-cluster-leader",
  "redis_setup_type": "leader",
  "role": "leader"
}

$ kubectl get svc/redis-cluster-follower-external-service -n redis-system -o=jsonpath='{.spec.selector}' | jq
{
  "app": "redis-cluster-follower",
  "redis_setup_type": "follower",
  "role": "follower"
}

์ด๋Š” Redis Cluster์˜ Helm template์—์„œ ์˜ค๋ฅ˜์˜ ์›์ธ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. leader์™€ follow์˜ external-service๋ฅผ ์ƒ์„ฑํ•˜๋Š” template๋ฅผ ๋ณด๋ฉด ์ด๋ฏธ ์œ„์—์„œ ํ™•์ธ ํ•œ๋ฐ”์™€ ๊ฐ™์ด redis_setup_type์˜ ๊ฐ’์ด leader์™€ follower๋กœ ์ •์˜ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€๋งŒ Redis Operator Controller๊ฐ€ rediscluster CR์˜ ์ƒ์„ฑ์„ ๊ฐ์ง€ํ•˜๊ณ  StatefulSet์„ ์ƒ์„ฑ ํ•  ๋•Œ Label์ด ์ž๋™์œผ๋กœ ์‚ฝ์ž…๋˜๋Š”๋ฐ Redis Cluster ๋ถ€๋ถ„์˜ controller ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด redis_setup_type์˜ label ๊ฐ’์ด cluster๋กœ prefix ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ Helm chart์— redis_setup_type์˜ label์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๊ณ  service object์˜ Label selector๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐ์„ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

$ kubectl patch svc/redis-cluster-leader-external-service -n redis-system -p '{"spec":{"selector":{"redis_setup_type":"cluster"}}}'
service/redis-cluster-leader-external-service patched

$ kubectl patch svc/redis-cluster-follower-external-service -n redis-system -p '{"spec":{"selector":{"redis_setup_type":"cluster"}}}'
service/redis-cluster-follower-external-service patched
$ redis-cli -h 192.168.1.184 -a redispassword cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
ba736d6a0fe48cf54290fd78ac3670079df7fe95 172.16.84.92:6379@16379 slave cb557203cc8779da78234cda345863db6ddca3ba 0 1655878128074 1 connected
7d5511d537ec147a6cb15cdd0c14a8d9d5d73044 172.16.10.88:6379@16379 master - 0 1655878130103 2 connected 5461-10922
162ed69a7cf46f58ff0d6c0dc5e80173a0999c36 172.16.78.111:6379@16379 myself,slave ae65d3acf8c9003ce07496b6d7d5ef4ef9e9f3a9 0 1655878129000 3 connected
39d7391b7ba0085513a5b7ed1d00f66f2cdbd425 172.16.10.93:6379@16379 slave 7d5511d537ec147a6cb15cdd0c14a8d9d5d73044 0 1655878129000 2 connected
cb557203cc8779da78234cda345863db6ddca3ba 172.16.84.81:6379@16379 master - 0 1655878129085 1 connected 0-5460
ae65d3acf8c9003ce07496b6d7d5ef4ef9e9f3a9 172.16.78.84:6379@16379 master - 0 1655878129084 3 connected 10923-16383

$ redis-cli -h 192.168.1.185 -a redispassword cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
7d5511d537ec147a6cb15cdd0c14a8d9d5d73044 172.16.10.88:6379@16379 master - 0 1655878134035 2 connected 5461-10922
cb557203cc8779da78234cda345863db6ddca3ba 172.16.84.81:6379@16379 myself,master - 0 1655878134000 1 connected 0-5460
ae65d3acf8c9003ce07496b6d7d5ef4ef9e9f3a9 172.16.78.84:6379@16379 master - 0 1655878135048 3 connected 10923-16383
162ed69a7cf46f58ff0d6c0dc5e80173a0999c36 172.16.78.111:6379@16379 slave ae65d3acf8c9003ce07496b6d7d5ef4ef9e9f3a9 0 1655878134542 3 connected
39d7391b7ba0085513a5b7ed1d00f66f2cdbd425 172.16.10.93:6379@16379 slave 7d5511d537ec147a6cb15cdd0c14a8d9d5d73044 0 1655878134000 2 connected
ba736d6a0fe48cf54290fd78ac3670079df7fe95 172.16.84.92:6379@16379 slave cb557203cc8779da78234cda345863db6ddca3ba 0 1655878135556 1 connected

โœ…  Redis Standalone mode๋Š” ๋ฌธ์ œ ์—†์ด ์ •์ƒ๋™์ž‘ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

 

Step 3. Monitoring

Step 3.1. Prometheus Monitoring

Redis Operator๋Š” redis-exporter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Prometheus ํ˜•์‹์œผ๋กœ redis ์„ค์ •์˜ metric์„ ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ, Redis Standalone/Cluster ๋ชจ๋‘ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

Helm chart๋ฅผ ํ†ตํ•ด redis-exporter๋ฅผ ํ™œ์„ฑํ™”ํ•˜์—ฌ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์‚ฌ์šฉ์ž ์ง€์ • values.yaml ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ์ƒ์„ธํ•œ ์„ค์ •์„ override๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (redisExporter ํ™œ์„ฑํ™” ๊ธฐ๋ณธ๊ฐ’์€ true ์ž…๋‹ˆ๋‹ค.)

redisExporter:
  enabled: true
  image: quay.io/opstree/redis-exporter:1.0
  imagePullPolicy: Always
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 100m
      memory: 128Mi
  env:
  - name: REDIS_EXPORTER_INCL_SYSTEM_METRICS
    value: "true"
  - name: REDIS_EXPORTER_PING_ON_CONNECT
    value: "true"
  - name: REDIS_EXPORTER_INCL_CONFIG_METRICS
    value: "true"
  - name: REDIS_EXPORTER_EXPORT_CLIENT_LIST
    value: "true"

redis-export๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ณ  leader์™€ follower์˜ Redis instance pod๋ฅผ describeํ•ด๋ณด๋ฉด redis-exporter๊ฐ€ sidecar container๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด ๋ณด์ž…๋‹ˆ๋‹ค.

$ kubectl describe pod/redis-cluster-leader-0 -n redis-system
Name:         redis-cluster-leader-0
Namespace:    redis-system
Priority:     0
Node:         k8s-w3-dragon/192.168.1.113
Start Time:   Wed, 22 Jun 2022 17:31:09 +0900
.
.
Containers:
redis-exporter:
    Container ID:   containerd://7acdf990af25a47975938d3a528c0c80c08502558f55c3b9e8a25df9922b10a0
    Image:          quay.io/opstree/redis-exporter:1.0
    Image ID:       quay.io/opstree/redis-exporter@sha256:d52aebf0ff162b5b953dfe7dfcb8a319748654fd7325007d93d2884e027edd2d
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 22 Jun 2022 17:31:11 +0900
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     100m
      memory:  128Mi
    Requests:
      cpu:     100m
      memory:  128Mi
    Environment:
      PERSISTENCE_ENABLED:                 true
      REDIS_ADDR:                          redis://localhost:6379
      REDIS_EXPORTER_EXPORT_CLIENT_LIST:   true
      REDIS_EXPORTER_INCL_CONFIG_METRICS:  true
      REDIS_EXPORTER_INCL_SYSTEM_METRICS:  true
      REDIS_EXPORTER_INCL_SYSTEM_METRICS:  true
      REDIS_EXPORTER_PING_ON_CONNECT:      true
      REDIS_PASSWORD:                      <set to the key 'password' in secret 'redis-secret'>  Optional: false
      SERVER_MODE:                         cluster
      SETUP_MODE:                          cluster
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-kdwfs (ro)
.
.
.
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  45m   default-scheduler  Successfully assigned redis-system/redis-cluster-leader-0 to k8s-w3-dragon
  Normal  Pulled     45m   kubelet            Container image "quay.io/opstree/redis:v6.2.5" already present on machine
  Normal  Created    45m   kubelet            Created container redis-cluster-leader
  Normal  Started    45m   kubelet            Started container redis-cluster-leader
  Normal  Pulling    45m   kubelet            Pulling image "quay.io/opstree/redis-exporter:1.0"
  Normal  Pulled     44m   kubelet            Successfully pulled image "quay.io/opstree/redis-exporter:1.0" in 841.273976ms
  Normal  Created    44m   kubelet            Created container redis-exporter
  Normal  Started    44m   kubelet            Started container redis-exporter

Step 3.2. ServiceMonitor(of Prometheus Operator)

redis-exporter ๋ฐฐํฌ ๋ฐ ๊ตฌ์„ฑ์ด ์™„๋ฃŒ ๋˜๋ฉด endpoint๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด Prometheus Target Configuration ์—…๋ฐ์ดํŠธ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

service endpoint๋ฅผ ์ˆ˜๋™์œผ๋กœ Prometheus ๋Œ€์ƒ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ณดํ†ต ์–ด๋ ค์šด๊ฒŒ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ Prometheus Operator์˜ ServiceMonitor CR๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ endpoint๋“ค์— ๋Œ€ํ•œ ๋Œ€์ƒ ๊ตฌ์„ฑ์„ ์ž๋™์œผ๋กœ ์„ค์ • ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Redis Standalone/Cluster์˜ Helm chart์—์„œ ServiceMonitor๋ฅผ ์ง€์›ํ•˜๊ณ  ์žˆ์–ด ์‚ฌ์šฉ์ž ์ง€์ • value.yaml ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ override ๋ฐฉ์‹์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

serviceMonitor:
  enabled: false
  interval: 30s
  scrapeTimeout: 10s
  namespace: redis-system # redis instance์™€ service object๊ฐ€ ๋ฐฐํฌ๋œ namespace

๋˜๋Š”, ServiceMonitor CR์„ yaml ํŒŒ์ผ๋กœ ์ •์˜ํ•˜์—ฌ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Redis Standalone

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      labels:
        app.kubernetes.io/component: middleware
        app.kubernetes.io/instance: redis-cluster
        app.kubernetes.io/name: redis-cluster
        app.kubernetes.io/version: 0.10.0
      name: redis-standalone-prometheus-monitoring
      namespace: redis-system
    spec:
      endpoints:
      - interval: 30s
        port: redis-exporter
        scrapeTimeout: 10s
      namespaceSelector:
        matchNames:
        - redis-system
      selector:
        matchLabels:
          app: redis-standalone
          redis_setup_type: standalone
  • Redis Cluster

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      labels:
        app.kubernetes.io/component: middleware
        app.kubernetes.io/instance: redis-cluster
        app.kubernetes.io/name: redis-cluster
        app.kubernetes.io/version: 0.10.0
      name: redis-cluster-leader-prometheus-monitoring
      namespace: redis-system
    spec:
      endpoints:
      - interval: 30s
        port: redis-exporter
        scrapeTimeout: 10s
      namespaceSelector:
        matchNames:
        - redis-system
      selector:
        matchLabels:
          app: redis-cluster-leader
          redis_setup_type: cluster
          role: leader

Prometheus Dashboard์— ์ ‘์†ํ•˜๋ฉด Targets์ด ์ถ”๊ฐ€๋˜์—ˆ๊ณ  ์ง€ํ‘œ(metric)๋“ค์„ ์ˆ˜์ง‘๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Prometheus_redis-exporter_metric-01.png

Prometheus_redis-exporter_metric-02.png

Step 3.3. Grafana Dashboard

Redis Cluster์˜ ํ†ต๊ณ„๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด Grafana Dashboard๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด ์•„๋ž˜ ๋งํฌ์—์„œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„ Grafana์— ๋“ฑ๋ก ํ•˜์—ฌ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”—  https://ot-container-kit.github.io/redis-operator/guide/grafana.html

Redis_Operator_Grafana-01.png

Redis_Operator_Grafana-02.png

 

Step 4. Redis Cluster Failover Testing

Redis Cluster์— master node 3๊ฐœ, replica node 3๊ฐœ๊ฐ€ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ 1๋ฒˆ master node (redis-cluster-leader-0)๋ฅผ ์‚ญ์ œํ•˜๋ฉด, 1๋ฒˆ replica node (redis-cluster-follower-01)๊ฐ€ master๋กœ ์Šน๊ฒฉ๋˜์–ด ์ง€์†์ ์œผ๋กœ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ cluster-node-time ์‹œ๊ฐ„์„ ํฌํ•จํ•ด์„œ ์ •์ƒ์œผ๋กœ ๋Œ์•„์˜ค๊ธฐ๊นŒ์ง€๋Š” ๋ช‡ ์ดˆ์˜ ์‹œ๊ฐ„์ด ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.

redis-cli ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ Redis Cluster์˜ 1๋ฒˆ master node์—์„œ dummy data๋ฅผ write ํ•ฉ๋‹ˆ๋‹ค.

$ kubectl exec -it redis-cluster-leader-0 -n redis-system -c redis-cluster-leader -- redis-cli -a redispassword -c set doik gradute
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
OK

๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ master(leader)์™€ replica(follower) nodes์—์„œ data๋ฅผ read ํ•˜๋ฉด ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ kubectl exec -it redis-cluster-follower-0 -n redis-system -c redis-cluster-follower -- redis-cli -a redispassword -c get doik
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"gradute"

$ kubectl exec -it redis-cluster-leader-2 -n redis-system -c redis-cluster-leader -- redis-cli -a redispassword -c get doik
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"gradute"

$ kubectl exec -it redis-cluster-follower-1 -n redis-system -c redis-cluster-follower -- redis-cli -a redispassword -c get doik
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"gradute"

dummy data๋ฅผ writeํ›„์— redis log๋ฅผ ๋ณด๋ฉด master node์—์„œ data writeing transition์ด ๋ฐœ์ƒ๊ณผ ๋™์‹œ์— replica node์— data๊ฐ€ replication ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • master 1๋ฒˆ ๋…ธ๋“œ(redis-cluster-leader-0 pod)์˜ redis log

    $ kubectl logs -f redis-cluster-leader-0 -n redis-system
    Defaulted container "redis-cluster-leader" out of: redis-cluster-leader, redis-exporter
    Starting redis service in cluster mode.....
    11:C 22 Jun 2022 14:27:20.230 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    11:C 22 Jun 2022 14:27:20.230 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=11, just started
    11:C 22 Jun 2022 14:27:20.230 # Configuration loaded
    11:M 22 Jun 2022 14:27:20.230 * monotonic clock: POSIX clock_gettime
    11:M 22 Jun 2022 14:27:20.231 * Node configuration loaded, I'm 7ded434ed7be8db05a7851dc44e082e38bbf398b
    11:M 22 Jun 2022 14:27:20.231 * Running mode=cluster, port=6379.
    11:M 22 Jun 2022 14:27:20.231 # Server initialized
    11:M 22 Jun 2022 14:27:20.231 * Ready to accept connections
    11:M 22 Jun 2022 14:28:40.238 # configEpoch set to 1 via CLUSTER SET-CONFIG-EPOCH
    11:M 22 Jun 2022 14:28:45.207 # Cluster state changed: ok
    11:M 22 Jun 2022 14:28:57.589 * Replica 172.16.84.121:6379 asks for synchronization
    11:M 22 Jun 2022 14:28:57.589 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '8e3ffd79b9f7370b05effda9a837c2956e5fabed', my replication IDs are 'd8bea88fcebd4c90442116e74a15a7fd2a3935d4' and '0000000000000000000000000000000000000000')
    11:M 22 Jun 2022 14:28:57.589 * Replication backlog created, my new replication IDs are '8e2dab8037c5e9c194cf0c659c9c28f77c08614e' and '0000000000000000000000000000000000000000'
    11:M 22 Jun 2022 14:28:57.589 * Starting BGSAVE for SYNC with target: disk
    11:M 22 Jun 2022 14:28:57.589 * Background saving started by pid 109
    109:C 22 Jun 2022 14:28:57.591 * DB saved on disk
    109:C 22 Jun 2022 14:28:57.591 * RDB: 0 MB of memory used by copy-on-write
    11:M 22 Jun 2022 14:28:57.619 * Background saving terminated with success
    11:M 22 Jun 2022 14:28:57.619 * Synchronization with replica 172.16.84.121:6379 succeeded
  • replica 1๋ฒˆ ๋…ธ๋“œ(redis-cluster-follower-0 pod)์˜ redis log

    $ kubectl logs -f redis-cluster-follower-0 -n redis-system
    Defaulted container "redis-cluster-follower" out of: redis-cluster-follower, redis-exporter
    Starting redis service in cluster mode.....
    13:C 22 Jun 2022 14:27:35.559 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    13:C 22 Jun 2022 14:27:35.559 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=13, just started
    13:C 22 Jun 2022 14:27:35.559 # Configuration loaded
    13:M 22 Jun 2022 14:27:35.560 * monotonic clock: POSIX clock_gettime
    13:M 22 Jun 2022 14:27:35.560 * Node configuration loaded, I'm 87fe6e67e43ddb9f9ad6acd830d360b83250c630
    13:M 22 Jun 2022 14:27:35.561 * Running mode=cluster, port=6379.
    13:M 22 Jun 2022 14:27:35.561 # Server initialized
    13:M 22 Jun 2022 14:27:35.561 * Ready to accept connections
    13:S 22 Jun 2022 14:28:57.588 * Before turning into a replica, using my own master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
    13:S 22 Jun 2022 14:28:57.588 * Connecting to MASTER 172.16.84.122:6379
    13:S 22 Jun 2022 14:28:57.588 * MASTER <-> REPLICA sync started
    13:S 22 Jun 2022 14:28:57.588 # Cluster state changed: ok
    13:S 22 Jun 2022 14:28:57.588 * Non blocking connect for SYNC fired the event.
    13:S 22 Jun 2022 14:28:57.589 * Master replied to PING, replication can continue...
    13:S 22 Jun 2022 14:28:57.589 * Trying a partial resynchronization (request 8e3ffd79b9f7370b05effda9a837c2956e5fabed:1).
    13:S 22 Jun 2022 14:28:57.590 * Full resync from master: 8e2dab8037c5e9c194cf0c659c9c28f77c08614e:0
    13:S 22 Jun 2022 14:28:57.590 * Discarding previously cached master state.
    13:S 22 Jun 2022 14:28:57.619 * MASTER <-> REPLICA sync: receiving 175 bytes from master to disk
    13:S 22 Jun 2022 14:28:57.619 * MASTER <-> REPLICA sync: Flushing old data
    13:S 22 Jun 2022 14:28:57.619 * MASTER <-> REPLICA sync: Loading DB in memory
    13:S 22 Jun 2022 14:28:57.620 * Loading RDB produced by version 6.2.5
    13:S 22 Jun 2022 14:28:57.620 * RDB age 0 seconds
    13:S 22 Jun 2022 14:28:57.620 * RDB memory usage when created 2.60 Mb
    13:S 22 Jun 2022 14:28:57.620 * MASTER <-> REPLICA sync: Finished with success
    13:S 22 Jun 2022 14:28:57.621 * Background append only file rewriting started by pid 83
    13:S 22 Jun 2022 14:28:57.650 * AOF rewrite child asks to stop sending diffs.
    83:C 22 Jun 2022 14:28:57.650 * Parent agreed to stop sending diffs. Finalizing AOF...
    83:C 22 Jun 2022 14:28:57.650 * Concatenating 0.00 MB of AOF diff received from parent.
    83:C 22 Jun 2022 14:28:57.651 * SYNC append only file rewrite performed
    83:C 22 Jun 2022 14:28:57.651 * AOF rewrite: 0 MB of memory used by copy-on-write
    13:S 22 Jun 2022 14:28:57.725 * Background AOF rewrite terminated with success
    13:S 22 Jun 2022 14:28:57.725 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
    13:S 22 Jun 2022 14:28:57.725 * Background AOF rewrite finished successfully

์ด์ œ failover(์žฅ์•  ์กฐ์น˜) ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ ํ•ด๋ณผํ…๋ฐ ๊ทธ์ „์— pods์˜ IP๋ฅผ ๊ธฐ์–ตํ•ด๋‘์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

$ kubectl get pod -n redis-system -o wide
NAME                       READY   STATUS    RESTARTS      AGE   IP              NODE            NOMINATED NODE   READINESS GATES
redis-cluster-follower-0   2/2     Running   0             1h    172.16.84.121   k8s-w3-dragon   <none>           <none>
redis-cluster-follower-1   2/2     Running   0             1h    172.16.10.75    k8s-w2-dragon   <none>           <none>
redis-cluster-follower-2   2/2     Running   0             1h    172.16.84.115   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-0     2/2     Running   0             1h    172.16.84.101   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-1     2/2     Running   0             1h    172.16.10.103   k8s-w2-dragon   <none>           <none>
redis-cluster-leader-2     2/2     Running   0             1h    172.16.78.67    k8s-w1-dragon   <none>           <none>
  • Master nodes
    • master 1 (redis-cluster-leader-0) : 172.16.84.101
    • master 2 (redis-cluster-leader-1) : 172.16.10.103
    • master 3 (redis-cluster-leader-2) : 172.16.78.67
  • Replica nodes
    • replica 1 (redis-cluster-follower-0) : 172.16.84.121
    • replica 2 (redis-cluster-follower-1) : 172.16.10.78
    • replica 3 (redis-cluster-follower-2) : 172.16.84.115

์ด์ œ 1๋ฒˆ master node (redis-cluster-leader-0 pod)์˜ image tag๋ฅผ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์ž„์œผ๋กœ ์žฅ์• ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒ ์Šต๋‹ˆ๋‹ค.

$ kubectl patch pod/redis-cluster-leader-0 -n redis-system -p '{"spec":{"containers":[{"name": "redis-cluster-leader","image": "quay.io/opstree/redis:v6.2.9"}]}}'

cluster_master_down_2.png

[์ด๋ฏธ์ง€ ์ถœ์ฒ˜] http://redisgate.kr/redis/cluster/cluster_failover.php

image tag๋ฅผ ๋ณ€๊ฒฝํ›„ 1๋ฒˆ master node(redis-cluster-leader-0 pod)์˜ ์ƒํƒœ๊ฐ€ ImagePullBackOff ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

$ kubectl get pod -n redis-system -o wide
NAME                       READY   STATUS             RESTARTS      AGE     IP              NODE            NOMINATED NODE   READINESS GATES
redis-cluster-follower-0   2/2     Running            0             15h     172.16.84.121   k8s-w3-dragon   <none>           <none>
redis-cluster-follower-1   2/2     Running            0             15h     172.16.10.75    k8s-w2-dragon   <none>           <none>
redis-cluster-follower-2   2/2     Running            0             15h     172.16.84.115   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-0     1/2     ImagePullBackOff   0 (47s ago)   2m21s   172.16.84.101   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-1     2/2     Running            0             15h     172.16.10.103   k8s-w2-dragon   <none>           <none>
redis-cluster-leader-2     2/2     Running            0             15h     172.16.78.67    k8s-w1-dragon   <none>           <none>

1๋ฒˆ master node(redis-cluster-leader-0 pod) : 172.16.84.101 ์—์„œ redis cluster nodes ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋ฉด, node fail ์ƒํƒœ๋กœ ์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ***1๋ฒˆ replica node(redis-cluster-follower-0 pod) : 172.16.84.121***๊ฐ€ master node๋กœ leader ์„ ์ถœ์— ๋”ฐ๋ผ ์Šน๊ฒฉ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

$ kubectl exec -it redis-cluster-leader-1 -n redis-system -c redis-cluster-leader -- redis-cli -a redispassword cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
5483f9be46324b9e8f48b431fc4128c788525cdc 172.16.10.103:6379@16379 myself,master - 0 1655964724000 2 connected 5461-10922
742149aba5d2e572b6f85ea59a964880fa79b367 172.16.78.67:6379@16379 master - 0 1655964724000 3 connected 10923-16383
a956b4aaf4a04957bc6b0a42bdb62122c91fb44e 172.16.84.115:6379@16379 slave 742149aba5d2e572b6f85ea59a964880fa79b367 0 1655964724864 3 connected
4d0bd6e99c00cddd6f9858da371526f39fef157a 172.16.10.75:6379@16379 slave 5483f9be46324b9e8f48b431fc4128c788525cdc 0 1655964725573 2 connected
87fe6e67e43ddb9f9ad6acd830d360b83250c630 ***172.16.84.121:6379@16379 master*** - 0 1655964725000 4 connected 0-5460
7ded434ed7be8db05a7851dc44e082e38bbf398b ***172.16.84.101:6379@16379 master,fail*** - 1655964668967 1655964667000 1 ***disconnected***

master๋กœ ์Šน๊ฒฉ๋œ ***1๋ฒˆ replica node(redis-cluster-follower-0 pod) : 172.16.84.121***์˜ redis log๋ฅผ ์ถœ๋ ฅํ•˜๋ฉด Failover election์— ๋”ฐ๋ผ ์ž๊ธฐ๊ฐ€ master๊ฐ€ ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

Failover election won: I'm the new master.

$ kubectl logs -f redis-cluster-follower-0 -n redis-system
.
.
.
13:S 23 Jun 2022 06:11:14.473 * Connecting to MASTER 172.16.84.101:6379
13:S 23 Jun 2022 06:11:14.473 * MASTER <-> REPLICA sync started
13:S 23 Jun 2022 06:11:14.473 # Error condition on socket for SYNC: Connection refused
13:S 23 Jun 2022 06:11:14.607 * FAIL message received from 742149aba5d2e572b6f85ea59a964880fa79b367 about 7ded434ed7be8db05a7851dc44e082e38bbf398b
13:S 23 Jun 2022 06:11:14.677 # Start of election delayed for 510 milliseconds (rank #0, offset 126).
13:S 23 Jun 2022 06:11:15.283 # Starting a failover election for epoch 4.
***13:S 23 Jun 2022 06:11:15.287 # Failover election won: I'm the new master.***
13:S 23 Jun 2022 06:11:15.287 # configEpoch set to 4 after successful failover
13:M 23 Jun 2022 06:11:15.287 * Discarding previously cached master state.
13:M 23 Jun 2022 06:11:15.287 # Setting secondary replication ID to 26d81a3e61a5425bfbab71716df5092c0d6deda8, valid up to offset: 127. New replication ID is 995090ede0799f7b0f13e5069b8ac40566902b0b

์ด์ œ 1๋ฒˆ master node๋Š” redis-cluster-leader-0 pod : 172.16.84.101์—์„œ redis-cluster-follower-0 pod : 172.16.84.121๋กœ ๋ณ€๊ฒฝ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์ด์ œ ์ž„์˜๋กœ ์žฅ์• ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ redis-cluster-leader-0 pod๋ฅผ ๋ณต์›ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

  1. master๋กœ ๋ณต์›(์Šน๊ฒฉ)๋œ๋‹ค.

  2. replica๋กœ ๋ณต์›๋œ๋‹ค.

  3. ์•„๋ฌด๋Ÿฐ ์˜ํ–ฅ๋„ ์—†๋‹ค.

ํ•œ๋ฒˆ ๋ณต์›ํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. image tag๋ฅผ ์›๋ž˜์˜ v6.2.5๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

$ kubectl patch pod/redis-cluster-leader-0 -n redis-system -p '{"spec":{"containers":[{"name": "redis-cluster-leader","image": "quay.io/opstree/redis:v6.2.5"}]}}'

cluster_master_down_2.png

pod์˜ ์ƒํƒœ๊ฐ€ ๋ณต์› ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ๋ณต์› ๋˜์—ˆ๋„ค์š”.

$ kubectl get pod -n redis-system -o wide
NAME                       READY   STATUS    RESTARTS      AGE   IP              NODE            NOMINATED NODE   READINESS GATES
redis-cluster-follower-0   2/2     Running   0             1h    172.16.84.121   k8s-w3-dragon   <none>           <none>
redis-cluster-follower-1   2/2     Running   0             1h    172.16.10.75    k8s-w2-dragon   <none>           <none>
redis-cluster-follower-2   2/2     Running   0             1h    172.16.84.115   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-0     2/2     Running   1 (3m ago)    3m    172.16.84.101   k8s-w3-dragon   <none>           <none>
redis-cluster-leader-1     2/2     Running   0             1h    172.16.10.103   k8s-w2-dragon   <none>           <none>
redis-cluster-leader-2     2/2     Running   0             1h    172.16.78.67    k8s-w1-dragon   <none>           <none>

redis cluster nodes์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ด๋ด…๋‹ˆ๋‹ค.

$ kubectl exec -it redis-cluster-leader-0 -n redis-system -c redis-cluster-leader -- redis-cli -a redispassword cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
5483f9be46324b9e8f48b431fc4128c788525cdc 172.16.10.103:6379@16379 master - 0 1655966203034 2 connected 5461-10922
7ded434ed7be8db05a7851dc44e082e38bbf398b 172.16.84.101:6379@16379 myself,slave 87fe6e67e43ddb9f9ad6acd830d360b83250c630 0 1655966203000 4 connected
87fe6e67e43ddb9f9ad6acd830d360b83250c630 172.16.84.121:6379@16379 master - 0 1655966202018 4 connected 0-5460
742149aba5d2e572b6f85ea59a964880fa79b367 172.16.78.67:6379@16379 master - 0 1655966204047 3 connected 10923-16383
a956b4aaf4a04957bc6b0a42bdb62122c91fb44e 172.16.84.115:6379@16379 slave 742149aba5d2e572b6f85ea59a964880fa79b367 0 1655966203000 3 connected
4d0bd6e99c00cddd6f9858da371526f39fef157a 172.16.10.75:6379@16379 slave 5483f9be46324b9e8f48b431fc4128c788525cdc 0 1655966203541 2 connected

๊ธฐ์กด node๋ฅผ ๋ณต์›ํ•˜๋”๋ผ๋„ master๋กœ ๋ณต์›๋˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ replica๋กœ ๋ณต์›๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰ master๊ฐ€ ์žฅ์• ํ›„ replica๊ฐ€ master๋กœ ์Šน๊ฒฉ๋œ ์ดํ›„์—๋Š” ์žฅ์• ๊ฐ€ ๋‚ฌ๋˜ master๋ฅผ ๋ณต์›ํ•˜๋”๋ผ๋„ ์ด๋ฏธ failover election์— ๋”ฐ๋ผ replica๊ฐ€ master๋กœ ์Šน๊ฒฉ์ด ๋˜์–ด๋ฒ„๋ฆฐ ์ƒํƒœ์—์„œ๋Š” ๋ณต์›๋œ node๋Š” replica์˜ ์—ญํ• ์ด ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ์•„๋ž˜๋Š” redis-cluster-follower-0๊ณผ redis-cluster-leader-0์˜ redis logs ์ž…๋‹ˆ๋‹ค.

$ kubectl logs -f redis-cluster-follower-0 -n redis-system -c redis-cluster-follower
.
.
.
13:M 23 Jun 2022 06:35:08.883 * Clear FAIL state for node 7ded434ed7be8db05a7851dc44e082e38bbf398b: master without slots is reachable again.
13:M 23 Jun 2022 06:35:08.885 * Replica 172.16.84.101:6379 asks for synchronization
13:M 23 Jun 2022 06:35:08.885 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '6d26e33239942b867bb6df23cee2c2171d556b0b', my replication IDs are '995090ede0799f7b0f13e5069b8ac40566902b0b' and '26d81a3e61a5425bfbab71716df5092c0d6deda8')
13:M 23 Jun 2022 06:35:08.885 * Starting BGSAVE for SYNC with target: disk
13:M 23 Jun 2022 06:35:08.901 * Background saving started by pid 61429
61429:C 23 Jun 2022 06:35:08.903 * DB saved on disk
61429:C 23 Jun 2022 06:35:08.903 * RDB: 0 MB of memory used by copy-on-write
13:M 23 Jun 2022 06:35:08.982 * Background saving terminated with success
13:M 23 Jun 2022 06:35:08.982 * Synchronization with replica 172.16.84.101:6379 succeeded
$ kubectl logs -f redis-cluster-leader-0 -n redis-system -c redis-cluster-leader
Starting redis service in cluster mode.....
11:C 23 Jun 2022 06:35:08.878 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
11:C 23 Jun 2022 06:35:08.878 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=11, just started
11:C 23 Jun 2022 06:35:08.878 # Configuration loaded
11:M 23 Jun 2022 06:35:08.879 * monotonic clock: POSIX clock_gettime
11:M 23 Jun 2022 06:35:08.879 * Node configuration loaded, I'm 7ded434ed7be8db05a7851dc44e082e38bbf398b
11:M 23 Jun 2022 06:35:08.879 * Running mode=cluster, port=6379.
11:M 23 Jun 2022 06:35:08.879 # Server initialized
11:M 23 Jun 2022 06:35:08.881 * DB loaded from append only file: 0.000 seconds
11:M 23 Jun 2022 06:35:08.881 * Ready to accept connections
11:M 23 Jun 2022 06:35:08.882 # Configuration change detected. Reconfiguring myself as a replica of 87fe6e67e43ddb9f9ad6acd830d360b83250c630
11:S 23 Jun 2022 06:35:08.882 * Before turning into a replica, using my own master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
11:S 23 Jun 2022 06:35:08.882 * Connecting to MASTER 172.16.84.121:6379
11:S 23 Jun 2022 06:35:08.882 * MASTER <-> REPLICA sync started
11:S 23 Jun 2022 06:35:08.882 # Cluster state changed: ok
11:S 23 Jun 2022 06:35:08.883 * Non blocking connect for SYNC fired the event.
11:S 23 Jun 2022 06:35:08.884 * Master replied to PING, replication can continue...
11:S 23 Jun 2022 06:35:08.884 * Trying a partial resynchronization (request 6d26e33239942b867bb6df23cee2c2171d556b0b:1).
11:S 23 Jun 2022 06:35:08.901 * Full resync from master: 995090ede0799f7b0f13e5069b8ac40566902b0b:126
11:S 23 Jun 2022 06:35:08.901 * Discarding previously cached master state.
11:S 23 Jun 2022 06:35:08.982 * MASTER <-> REPLICA sync: receiving 194 bytes from master to disk
11:S 23 Jun 2022 06:35:08.982 * MASTER <-> REPLICA sync: Flushing old data
11:S 23 Jun 2022 06:35:08.983 * MASTER <-> REPLICA sync: Loading DB in memory
11:S 23 Jun 2022 06:35:08.983 * Loading RDB produced by version 6.2.5
11:S 23 Jun 2022 06:35:08.983 * RDB age 0 seconds
11:S 23 Jun 2022 06:35:08.984 * RDB memory usage when created 2.54 Mb
11:S 23 Jun 2022 06:35:08.984 * MASTER <-> REPLICA sync: Finished with success
11:S 23 Jun 2022 06:35:08.984 * Background append only file rewriting started by pid 16
11:S 23 Jun 2022 06:35:09.026 * AOF rewrite child asks to stop sending diffs.
16:C 23 Jun 2022 06:35:09.026 * Parent agreed to stop sending diffs. Finalizing AOF...
16:C 23 Jun 2022 06:35:09.026 * Concatenating 0.00 MB of AOF diff received from parent.
16:C 23 Jun 2022 06:35:09.026 * SYNC append only file rewrite performed
16:C 23 Jun 2022 06:35:09.026 * AOF rewrite: 0 MB of memory used by copy-on-write
11:S 23 Jun 2022 06:35:09.083 * Background AOF rewrite terminated with success
11:S 23 Jun 2022 06:35:09.083 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
11:S 23 Jun 2022 06:35:09.083 * Background AOF rewrite finished successfully
11:S 23 Jun 2022 06:50:09.009 * 1 changes in 900 seconds. Saving...
11:S 23 Jun 2022 06:50:09.010 * Background saving started by pid 969
969:C 23 Jun 2022 06:50:09.011 * DB saved on disk
969:C 23 Jun 2022 06:50:09.012 * RDB: 0 MB of memory used by copy-on-write
11:S 23 Jun 2022 06:50:09.111 * Background saving terminated with success

 

Step 5. Redis Cluster TCP ports

๋ชจ๋“  Redis Cluster๋Š” ๋‘๊ฐœ์˜ TCP connection์„ ํ•„์š”๋กœ ํ•˜๋ฉฐ, Cluster๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ Redis instances๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  Redis instance๊ณผ Gassip Protocol์„ ์‚ฌ์šฉํ•˜์—ฌ redis ์ƒํƒœ ์ •๋ณด๋ฅผ ๊ตํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ Redis TCP Port(6379)๋Š” Client๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋ฉฐ, ์—ฌ๊ธฐ์— 10000์„ ๋”ํ•ด Redis instance(node)๊ฐ„์— ํ†ต์‹ ์„ ์œ„ํ•œ Cluster Bus Port(16379)๋ฅผ ์ถ”๊ฐ€๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

Master ๋…ธ๋“œ๊ฐ€ ๋‹ค์šด๋˜๋ฉด gassip protocol์„ ์ด์šฉํ•ด redis ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ  replica์ค‘ ํ•˜๋‚˜๋ฅผ master๋กœ ์Šน๊ฒฉ์‹œํ‚ค๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Cluster Bus Port

  • Cluster Bus Port๋Š” node-to-node ํ†ต์‹  ์ฑ„๋„๋กœ ์‚ฌ์šฉ
  • failure detection, configuration update, failover authorization ๋“ฑ์— ์‚ฌ์šฉ
  • Clint๋Š” Redis TCP Port(6379)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜์ง€๋งŒ, Redis Cluster์˜ node-to-node ํ†ต์‹ ์„ ์œ„ํ•ด Cluster Bus Port(16379)๋ฅผ ๋ฐฉํ™”๋ฒฝ์—์„œ ํ—ˆ์šฉ ํ•„์š”

Redis_Cluster_TCP_ports.png

[์ด๋ฏธ์ง€ ์ถœ์ฒ˜] https://alibaba-cloud.medium.com/understanding-the-failover-mechanism-of-redis-cluster-3b979dcf3441

 

Official Website

 

Reference

 

END

โš ๏ธ **GitHub.com Fallback** โš ๏ธ