Как стать автором
Обновить

Масштабируем приложение в Kubernetes с KEDA (без Prometheus)

Время на прочтение6 мин
Количество просмотров5.8K

На хабре уже был перевод одной из статей о KEDA. В ней автор делится делится информацией о проекте, о том как KEDA интегрируется с Prometheus, и как можно масштабировать свое демо-приложение на базе метрик получаемых с Redis, работающего внутри того же Kubernetes-кластера.

В данной статье я постараюсь быть кратким. Вместе мы познакомимся с KEDA на реальном примере всего за несколько минут. Prometheus нам не пригодится.

Немного введения

Все знают, что Kubernetes отлично работает со stateless-приложениями. Особо серьезные ребята даже запускают базы данных в кубере, а самые смелые даже в продакшне. Но чаще всего в проде используются сервисы типа RDS или же БД развернутые за пределами Kubernetes-кластера.

Для тех кто хочет масштабировать свои приложения внутри Kubernetes, но при этом использовать какие-то внешние метрики (например кол-во сообщений в AWS SQS или Kafka, соединений в PostgreSQL/MySQL/и т.д) необходимо использовать внешние (external) метрики. Чаще всего это реализуется импортом метрик в Prometheus, с помощью различных адаптеров, и последующим масштабированием приложения на основе метрик в проме.

Так вот, KEDA позволяет нам немного упростить этот процесс, не обращаясь за метриками в Prometheus. Все что нам нужно, задеплоить несколько CRD-шек, пару-тройку ямлов для описания масштабирования и доступов. В общем, сейчас покажу.

Как работает KEDA, взято отсюда: https://www.codit.eu/blog/exploring-kubernetes-based-event-driven-autoscaling-keda/
Как работает KEDA, взято отсюда: https://www.codit.eu/blog/exploring-kubernetes-based-event-driven-autoscaling-keda/

Установка KEDA

Я провожу свои эксперименты на macOS, с установленным Docker for Mac. Можете использовать все что угодно, любой кубер подойдет.

Установка KEDA простая, я использую helm:

$ helm repo add kedacore https://kedacore.github.io/charts
$ helm repo update
$ helm install keda kedacore/keda --namespace keda --create-namespace

Задеплоили чарт, смотрим что под KEDA-оператора и метрикc-сервера поднялись:

$ kubectl get po -n keda
NAME                                               READY   STATUS    RESTARTS   AGE
keda-operator-7fc5699d47-ng7rk                     1/1     Running   0          75s
keda-operator-metrics-apiserver-57fc85685f-zqnzr   1/1     Running   0          75s

$ kubectl get apiservices v1beta1.external.metrics.k8s.io
NAME                              SERVICE                                AVAILABLE   AGE
v1beta1.external.metrics.k8s.io   keda/keda-operator-metrics-apiserver   True        95s

Все, KEDA-оператор установлен, идем дальше.

Задеплоим "Hello World"

У Kubernetes свой "Hello World", это деплоймент nginx, давайте идти по канонам и задеплоим его:

$ kubectl create ns nginx-demo
$ kubectl apply -n nginx-demo -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/controllers/nginx-deployment.yaml

Проверим состояние подов:

$ kg po -n nginx-demo
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-2g24q   1/1     Running   0          36s
nginx-deployment-66b6c48dd5-67kgv   1/1     Running   0          36s
nginx-deployment-66b6c48dd5-fj4lq   1/1     Running   0          36s

Все хорошо, в этом деплойменте 3 пода, как и положено.

Давайте сделаем так, чтобы поды масштабировались в зависимости от количества сообщений в очереди RabbitMQ.

На данный момент KEDA поддерживает 36 различных источников, на основе которых можно масштабироваться, в моем примере я выбрал RabbitMQ, просто потому что так захотел.

Немного подготовки RabbitMQ

Как я уже упоминал ранее, свои тесты я делаю на локальной машине с Docker for Mac, поэтому я хочу сымитировать реальную ситуацию, когда RabbitMQ запускается не внутри Kubernetes, а, скажем, в другой сети. Поэтому его я буду устанавливать просто через brew-пакет. Но перед этим, давайте запишем IP-адрес моей локальной машины, он нам скоро пригодится:

$ ipconfig getifaddr en0
192.168.2.101

Все, устанавливаем RabbitMQ и стартуем его:

$ brew install rabbitmq
$ RABBITMQ_NODE_IP_ADDRESS=0.0.0.0 /usr/local/sbin/rabbitmq-server 
  ...
  ##  ##      RabbitMQ 3.8.19
  ##  ##
  ##########  Copyright (c) 2007-2021 VMware, Inc. or its affiliates.
  ######  ##
  ##########  Licensed under the MPL 2.0. Website: https://rabbitmq.com
  ...
  Starting broker... completed with 6 plugins.

Убедимся что все поднялось:

$ /usr/local/sbin/rabbitmqadmin -H 127.0.0.1 -u guest -p guest \
    list connections
No items

Все хорошо. Единственный момент, что доступ под стандартным пользователем guest доступен только по адресу 127.0.0.1, поэтому нужно добавить нового пользователя, скажем (demo/demo), ну и создать очередь (demo_queue) для тестирования:

$ /usr/local/sbin/rabbitmqadmin --host 127.0.0.1 -u guest -p guest \
    declare user name=demo password=demo tags=administrator
user declared

$ /usr/local/sbin/rabbitmqadmin --host 127.0.0.1 -u guest -p guest \
    declare permission vhost=/ user=demo configure=".*" write=".*" read=".*"
permission declared

$ /usr/local/sbin/rabbitmqadmin --host 127.0.0.1 -u guest -p guest \
    declare queue name=demo_queue
queue declared

После этого мы можем подключаться по "внешнему" IP-адресу к кролику:

$ /usr/local/sbin/rabbitmqadmin -H 192.168.2.101 -u demo -p demo \
    list queues
+------------+----------+
|    name    | messages |
+------------+----------+
| demo_queue | 0        |
+------------+----------+

Немного YAML

RabbitMQ готов, теперь нужно подключить к нему KEDA, для этого нам надо задеплоить три объекта:

  • Secret — в нем будет храниться строка подключения к RabbitMQ, в таком виде: amqp://demo:demo@192.168.2.101:5672/

  • TriggerAuthentication — объект для аутентификации, который использует данные из секрета выше

  • ScaledObject — собственно тот самый объект, в котором мы можем настраивать различные параметры масштабирования

Деплоим:

$ cat <<EOF | kubectl apply -n nginx-demo -f -
---
apiVersion: v1
kind: Secret
metadata:
  name: keda-rabbitmq-secret
data:
  host: YW1xcDovL2RlbW86ZGVtb0AxOTIuMTY4LjIuMTAxOjU2NzIv # echo -n amqp://demo:demo@192.168.2.101:5672/ | base64
---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: keda-trigger-auth-rabbitmq-conn
spec:
  secretTargetRef:
    - parameter: host
      name: keda-rabbitmq-secret # Имя нашего секрета
      key: host
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: rabbitmq-scaledobject
spec:
  scaleTargetRef:
    name: nginx-deployment # Имя nginx-деплоймента который хотим масштабировать
  minReplicaCount: 1       # Меньше одной реплики не хотим
  maxReplicaCount: 5       # А то же время больше пяти тоже
  pollingInterval: 10      # Как часто ходить за метрикой
  cooldownPeriod:  120     # Сколько времени ждать для даунскейла
  triggers:
  - type: rabbitmq
    metadata:
      protocol: amqp
      queueName: demo_queue # Наша демо-очередь
      mode: QueueLength
      value: "3" # Если в очереди три новых сообщения — добавляем под
    authenticationRef:
      name: keda-trigger-auth-rabbitmq-conn
EOF

Проверяем что все работает:

$ kubectl get scaledobject                      
NAME                    SCALETARGETKIND      SCALETARGETNAME    MIN   MAX   TRIGGERS   AUTHENTICATION                    READY   ACTIVE   AGE
rabbitmq-scaledobject   apps/v1.Deployment   nginx-deployment   1     5     rabbitmq   keda-trigger-auth-rabbitmq-conn   True    False    14m

$ kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-24qp7   1/1     Running   0          3m46s

$ kubectl get hpa
NAME                             REFERENCE                     TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-rabbitmq-scaledobject   Deployment/nginx-deployment   0/3 (avg)   1         5         1          12m

Тестируем

Давайте отправим 5 сообщений в нашу очередь в RabbitMQ:

$ for i in {1..5}; do
    /usr/local/sbin/rabbitmqadmin --host 192.168.2.101 -u demo -p demo \
        publish exchange=amq.default routing_key=demo_queue payload="message ${i}"
done

$ /usr/local/sbin/rabbitmqadmin -H 192.168.2.101 -u demo -p demo \
    list queues
+------------+----------+
|    name    | messages |
+------------+----------+
| demo_queue | 5        |
+------------+----------+

Подождем 10 секунд пока KEDA сходит за метрикой и проверим наши поды (мы ожидаем увидеть 2 пода, так как скейлимся по 1 поду, на каждые 3 сообщения в очереди):

$ kubectl get hpa
NAME                             REFERENCE                     TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-rabbitmq-scaledobject   Deployment/nginx-deployment   5/3 (avg)   1         5         1          22m

$ kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-24qp7   1/1     Running   0          14m
nginx-deployment-66b6c48dd5-2d4w2   1/1     Running   0          66s

Давайте подбавим газку, добавим еще 7 сообщений в очередь:

$ for i in {6..12}; do
    /usr/local/sbin/rabbitmqadmin --host 192.168.2.101 -u demo -p demo \
        publish exchange=amq.default routing_key=demo_queue payload="message ${i}"
done

$ /usr/local/sbin/rabbitmqadmin -H 192.168.2.101 -u demo -p demo \
    list queues
+------------+----------+
|    name    | messages |
+------------+----------+
| demo_queue | 12       |
+------------+----------+

12 сообщений в очереди, по идее уже 4 пода должно работать, проверяем:

$ kubectl get hpa
NAME                             REFERENCE                     TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-rabbitmq-scaledobject   Deployment/nginx-deployment   12/3 (avg)  1         5         2          24m

$ kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-24qp7   1/1     Running   1          17m
nginx-deployment-66b6c48dd5-78d54   1/1     Running   0          38s
nginx-deployment-66b6c48dd5-jxtr8   1/1     Running   0          38s
nginx-deployment-66b6c48dd5-sl4p8   1/1     Running   0          38s

Теперь очистим очередь, количество подов должно опуститься до минимального значения (что в нашем случае 1 под):

$ /usr/local/sbin/rabbitmqadmin -H 192.168.2.101 -u demo -p demo \
    purge queue name=demo_queue
queue purged

$ /usr/local/sbin/rabbitmqadmin -H 192.168.2.101 -u demo -p demo \
    list queues
+------------+----------+
|    name    | messages |
+------------+----------+
| demo_queue | 0        |
+------------+----------+

$ kubectl get hpa
NAME                             REFERENCE                     TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-rabbitmq-scaledobject   Deployment/nginx-deployment   0/3 (avg)   1         5         1          28h

$ kubectl get po 
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-24qp7   1/1     Running   0          20m

Все хорошо, масштабируется и вверх и вниз, как и ожидалось.

Приберемся за собой после экспериментов:

$ helm uninstall keda -n keda
$ kubectl delete ns keda
$ kubectl delete ns nginx-demo

Как видите, Prometheus нам не пригодился, все максимально просто. Если пропустить момент с настройкой RabbitMQ, то процесс деплоя и тестирования KEDA занимает буквально несколько минут.

Ссылки

Теги:
Хабы:
+12
Комментарии4

Публикации

Истории

Работа

DevOps инженер
45 вакансий

Ближайшие события