Задача — запустить Redis в Kubernetes.
Используем Master-Slave репликацию и Sentinel для мониторинга и failover.
См. Redis: репликация, часть 2 — Master-Slave репликация, и Redis Sentinel.
Содержание
Redis cluster vs Redis replication
См. Redis: репликация, часть 1 — обзор. Replication vs Sharding. Sentinel vs Cluster. Топология Redis и Choose between Redis Helm Chart and Redis Cluster Helm Chart.
Вкратце:
- Replica — включает в себя Redis Master, который выполняет чтение-запись, и копирует данные на Redis Slaves, которые обслуживает запросы на чтение. При этом слейвы могут заменить мастера, если он упадёт
- Cluster — имеет смысл, если у вас данных больше, чем памяти на отдельном сервере. Кластер умеет Sharding, и клиент, запрашивающий определённый ключ, будет направлен на ту ноду, которая этот ключ хранит.
Варианты запуска Redis в Kubernetes
Что надо — это Redis с репликацией.
Как можно реализовать:
- ручной сетап — см. How to Create a Primary-Replica Redis Cluster in Kubernetes
- Redis Operator — redis-operator
- Helm чарт с кластером — https://bitnami.com/stack/redis-cluster
- Helm чарт с обычной репликацией мастер-слейв — https://bitnami.com/stack/redis
Что нам упрощает жизнь, так это то, что нам не нужна персистентность данных — наш Redis будет использоваться толкьо для хранения кеша, который при рестарте можно терять, а значит — не будет лишней головной боли с Kubernetes PersistentVolume.
Helm chart deploy
Сначала запустим все сервисы, посмотрим на них, потом перейдём к доступным опциям.
Добавляем репоизторий Bitnami:
[simterm]
$ helm repo add bitnami https://charts.bitnami.com/bitnami "bitnami" has been added to your repositories
[/simterm]
Деплоим Redis:
[simterm]
$ helm install backend-redis bitnami/redis NAME: backend-redis LAST DEPLOYED: Tue Sep 22 14:48:02 2020 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: ** Please be patient while the chart is being deployed ** Redis can be accessed via port 6379 on the following DNS names from within your cluster: backend-redis-master.default.svc.cluster.local for read/write operations backend-redis-slave.default.svc.cluster.local for read-only operations To get your password run: export REDIS_PASSWORD=$(kubectl get secret --namespace default backend-redis -o jsonpath="{.data.redis-password}" | base64 --decode) To connect to your Redis server: 1. Run a Redis pod that you can use as a client: kubectl run --namespace default backend-redis-client --rm --tty -i --restart='Never' \ --env REDIS_PASSWORD=$REDIS_PASSWORD \ --image docker.io/bitnami/redis:6.0.8-debian-10-r0 -- bash 2. Connect using the Redis CLI: redis-cli -h backend-redis-master -a $REDIS_PASSWORD redis-cli -h backend-redis-slave -a $REDIS_PASSWORD To connect to your database from outside the cluster execute the following commands: kubectl port-forward --namespace default svc/backend-redis-master 6379:6379 & redis-cli -h 127.0.0.1 -p 6379 -a $REDIS_PASSWORD
[/simterm]
Получаем пароль, который был сгенерирован во время установки чарта:
[simterm]
$ kubectl get secret --namespace default backend-redis -o jsonpath="{.data.redis-password}" | base64 --decode TySS43UhAW
[/simterm]
Запускаем port-forward
, что бы подключиться к поду с Redis master:
[simterm]
$ kubectl port-forward --namespace default svc/backend-redis-master 6379:6379 Forwarding from [::1]:6379 -> 6379 Forwarding from 127.0.0.1:6379 -> 6379
[/simterm]
Подключаемся:
[simterm]
$ redis-cli -h 127.0.0.1 -p 6379 -a TySS43UhAW Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379>
[/simterm]
«It works!» (с)
Проверяем сеть:
[simterm]
$ kk get svc redis-service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE redis-service NodePort 172.20.119.242 <none> 6379:32445/TCP 117d
[/simterm]
NodePort
, а нам требуется LoadBalancer
.
Кроме того — нам требуется Redis Sentinel, а по дефолту он:
sentinel.enabled |
Enable sentinel containers | false |
Окей, переходим к опциям — включим Sentinel и LoadBalancer.
Redis Options
Что нам потребуется из опций:
- global.redis.password
- metrics:
- metrics.enabled
- metrics.serviceMonitor.enabled
- metrics.serviceMonitor.namespace
- Persiste:
- master.persistence.enabled
- slave.persistence.enabled
- Service
- master.service.type
- master.service.annotations
- slave.service.type
- slave.service.annotations
- Sentinel
- sentinel.enabled
- sentinel.service.type — need for LBso clients can ask for Master/Slaves
- sentinel.service.annotations
Создаём файл с параметрами ~/Temp/redis-opts.yaml
:
global: redis: password: "blablacar" metrics: enabled: true serviceMonitor: enabled: true namespace: "monitoring" master: persistence: enabled: false service: type: LoadBalancer annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internal slave: persistence: enabled: false service: type: LoadBalancer annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internal sentinel: enabled: true service: type: LoadBalancer annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internal
Обновляем деплоймет, через -f
указываем файл с параметрами:
[simterm]
$ helm upgrade --install backend-redis bitnami/redis -f ~/Temp/redis-opts.yaml
[/simterm]
Проверим пароль:
[simterm]
$ kubectl get secret --namespace default backend-redis -o jsonpath="{.data.redis-password}" | base64 --decode blablacar
[/simterm]
Лоад-балансеры:
[simterm]
$ kk get svc -l app=redis NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE backend-redis LoadBalancer 172.20.204.235 af5e1294a4a73426692c7e25f7bb947d-915967.us-east-2.elb.amazonaws.com 6379:30647/TCP,26379:32523/TCP 80s backend-redis-headless ClusterIP None <none> 6379/TCP,26379/TCP 80s backend-redis-metrics ClusterIP 172.20.66.2 <none> 9121/TCP 80s
[/simterm]
Коннект:
[simterm]
$ redis-cli -h af5e1294a4a73426692c7e25f7bb947d-915967.us-east-2.elb.amazonaws.com -a blablacar Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. af5e1294a4a73426692c7e25f7bb947d-915967.us-east-2.elb.amazonaws.com:6379>
[/simterm]
Работает.
Но почему LoadBalancer публичный, если указывали тип internal?
А потому что аннотация alb.ingress.kubernetes.io/scheme: internal
— для ALB Ingress Controller, а мы создаём простой Kubernetes Service с типом LoadBalancer
, который создаёт AWS Classic Load Balancer.
Читаем доку https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer, обновим аннотации: вместо «alb.ingress.kubernetes.io/scheme: internal
» — указываем «service.beta.kubernetes.io/aws-load-balancer-internal: "true"
«:
... master: service: type: LoadBalancer annotations: service.beta.kubernetes.io/aws-load-balancer-internal: "true" slave: service: type: LoadBalancer annotations: service.beta.kubernetes.io/aws-load-balancer-internal: "true" sentinel: enabled: true service: type: LoadBalancer annotations: service.beta.kubernetes.io/aws-load-balancer-internal: "true"
Обновляекм, проверяем:
[simterm]
$ kk get svc -l app=redis NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE backend-redis LoadBalancer 172.20.178.72 internal-***-1786016015.us-east-2.elb.amazonaws.com 6379:31192/TCP,26379:32239/TCP 17s backend-redis-headless ClusterIP None <none> 6379/TCP,26379/TCP 17s backend-redis-metrics ClusterIP 172.20.35.163 <none> 9121/TCP 17s
[/simterm]
Проверим запись данных — должен пойти через Master-инстанс:
[simterm]
admin@bttrm-dev-app-1:~$ redis-cli -h internal-***-1786016015.us-east-2.elb.amazonaws.com -p 6379 -a blablacar SET testkey testvalue OK
[/simterm]
Чтение данных:
[simterm]
admin@bttrm-dev-app-1:~$ redis-cli -h internal-***-1786016015.us-east-2.elb.amazonaws.com -p 6379 -a blablacar GET testkey "testvalue"
[/simterm]
Статус репликации:
[simterm]
admin@bttrm-dev-app-1:~$ redis-cli -h internal-***-1786016015.us-east-2.elb.amazonaws.com -p 6379 -a blablacar info replication # Replication role:master connected_slaves:1 slave0:ip=10.3.50.119,port=6379,state=online,offset=144165,lag=1 ...
[/simterm]
И статус Sentinel:
[simterm]
admin@bttrm-dev-app-1:~$ redis-cli -h internal-***-1786016015.us-east-2.elb.amazonaws.com -p 26379 -a blablacar info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=10.3.33.107:6379,slaves=1,sentinels=2
[/simterm]
Хотя вообще, запись на Мастер должна выполняться через получения адреса Мастера у одного из Сентинелов:
[simterm]
admin@bttrm-dev-app-1:~$ redis-cli -h internal-***-1786016015.us-east-2.elb.amazonaws.com -p 26379 -a blablacar sentinel get-master-addr-by-name mymaster 1) "10.3.33.107" 2) "6379"
[/simterm]
См. документацию тут>>>.
Готово.