Масштабируем приложение в Kubernetes от метрики в Yandex Monitoring (или от любого http-эндпоинта)

от автора

Всем привет! Меня зовут Дмитрий Мамонтов, я DevOps-инженер с опытом работы более пяти лет, а также наставник на курсе «DevOps для эксплуатации и разработки» и один из авторов курса «Эксплуатация и разработка в Kubernetes» в Яндекс Практикуме.

Представим, что у нас есть приложение, которое шлёт свои метрики в Yandex Monitoring, и стоит задача: масштабировать это приложение с помощью HPA в кластере Kubernetes в зависимости от метрики.

Есть два популярных варианта решения этой задачи:

  1. Настроить интеграцию с prometheus-adapter и перекладывать метрики в Prometheus из Yandex Monitoring. Для этого метода нам необходим установленный Prometheus и prometheus-adapter. Prometheus будет опрашивать Yandex Monitoring, а адаптер будет отдавать метрику для работы HPA .

  2. Использовать Keda-operator. В данном случае опрашивать Yandex Monitoring будет Keda и сама управлять работой HPA. Воспользуемся этим вариантом.

Генерация тестовых метрик

Если приложения у нас нет под рукой, а попробовать хочется, то можно воспользоваться примером из документации или сгенерировать несколько значений метрик с помощью утилитыcurl.

  1. Логинимся в облако с помощью yc и выписываем токен.

yc init yc iam create-token
  1. Отправим несколько метрик запросом вида, подставив значение folder и токена:

curl -X POST \   'https://monitoring.api.cloud.yandex.net/monitoring/v2/data/write?folderId=ВАШФОЛДЕР&service=custom' \   -H "Authorization: Bearer ВАШТОКЕН" \   -H "Content-Type: application/json" \   -d '{     "metrics": [         {             "name": "trigger_metric",             "labels": {                 "foo": "bar"             },             "value": 1000         }     ] }'

Ответ будет вида:

{"writtenMetricsCount":1}

На графике будут видны метрики:

Метрик лучше сгенерировать несколько штук для наглядности

Метрик лучше сгенерировать несколько штук для наглядности

Приступаем к настройке масштабирования

Установку k8s (в облаке или вне его) я пропущу. В Яндексе можно поднять как через веб-консоль (или yc), так и с помощью terraform-провайдера.

Управлять масштабированием будем с помощью KEDA.
KEDA — это компонент для Kubernetes, который расширяет возможности горизонтального масштабирования (HPA). Он позволяет масштабировать приложения на основе событий или метрик от внешних источников, таких как очереди сообщений, базы данных, сервисы мониторинга и другие.

Для его настройки в нашем примере необходимо поставить оператор и настроить обращения в Yandex Monitoring.
Приступим:

Процесс установки оператора описан тут. Воспользуемся готовым helm-чартом.

# Добавим репозиторий чартов $ helm repo add kedacore  https://kedacore.github.io/charts $ helm repo update # Установим оператора Keda: # При желании, можно поправить\посмотреть параметры установки в values $ helm show values kedacore/keda $ helm install keda kedacore/keda --namespace keda --create-namespace

Итого получим установленный оператор:

$ kubectl get po -n keda NAME                                              READY   STATUS    RESTARTS        AGE keda-admission-webhooks-85bfd658f5-55zhf          1/1     Running   0               4h16m keda-operator-c6f875576-465sm                     1/1     Running   1 (4h16m ago)   4h16m keda-operator-metrics-apiserver-6d5b8869f-w6lz2   1/1     Running   0 

Приступаем к интеграции с Yandex Monitoring.

Сначала установим тестовое приложение, которое будем масштабировать (если у вас его ещё нет).

apiVersion: apps/v1 kind: Deployment metadata:   name: simple-app   labels:     app: nginx spec:   replicas: 3 # изначально будет 3 пода   selector:     matchLabels:       app: nginx   template:     metadata:       labels:         app: nginx     spec:       containers:       - name: nginx         image: nginx:latest

Запустим его в неймспейсе по-умолчанию:

kubectl apply -f deploy.yaml

Метрику будем забирать по http в формате prometheus.
Для наших целей такой способ отлично подойдет так, как нам для принятия решения о масштабировании нужно именно последнее значение.
Чтобы обратиться к API за метрикой нам необходим будет статический API KEY. Для этого необходимо создать сервис-аккаунт с привилегией monitoring.viewer и выписать ключ от его имени.

Создание ключа для обращения по API

Создание ключа для обращения по API

С помощью curl можно получить значение так (не забудьте подставить ключ и фолдер):

$ curl "https://monitoring.api.cloud.yandex.net/monitoring/v2/prometheusMetrics?folderId=ВАШФОЛДЕР&service=custom" \   -H "Authorization: Bearer ВАШ APIKEY" # TYPE trigger_metric gauge trigger_metric{foo="bar"} 1000.0

Далее нам нужно описать сущность ScaledObject, настроить скейлер Metric-api и поместить токен для доступа к метрикам в секрет.
Вообще, Keda имеет очень много скейлеров, которые позволяют интегрировать её с почти любой базой данных или системой мониторинга.

Обратите внимание, что версия API в альфе и может поменяться в новой версии контроллера.

apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata:   name: my-scaler spec:   scaleTargetRef:     name: simple-nginx   pollingInterval: 5  # Как часто опрашивать. Default: 30 seconds   cooldownPeriod:  10 # Сколько ждать после изменения. Default: 300 seconds   minReplicaCount: 1  # Минимальное значение   maxReplicaCount: 5  # Максимальное значение   triggers:     - type: metrics-api       metadata:         targetValue: "200.0" # После какого значения метрики начинаем увеличивать\уменьшать поды         activationTargetValue: "50.0" # Можно установить значения для активации\деактивации ScaledObject         format: "prometheus"         url: "https://monitoring.api.cloud.yandex.net/monitoring/v2/prometheusMetrics?folderId=ВАШФОЛДЕР&service=custom" # урл, где искать метрику         valueLocation: "trigger_metric{foo=\"bar\"}" # не забываем экранировать кавычки         authMode: "bearer"       authenticationRef:         name: keda-metric-api-creds  --- apiVersion: keda.sh/v1alpha1 kind: TriggerAuthentication metadata:   name: keda-metric-api-creds spec:   secretTargetRef:     - parameter: token       name: keda-metric-api-secret       key: token --- apiVersion: v1 kind: Secret metadata:   name: keda-metric-api-secret data:   token: "ТОКЕН APIKEY ЗАШИФРОВАННЫЙ В BASE64"

Деплоим вышеописанные манифесты:

$ kubectl apply -f scale.yml

Проверяем:

$ kubectl get scaledobject NAME        SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS      AUTHENTICATION          READY   ACTIVE   FALLBACK   PAUSED    AGE my-scaler   apps/v1.Deployment   simple-nginx      1     5     metrics-api   keda-metric-api-creds   True    True     False      Unknown   51m  $ kubectl get hpa NAME                 REFERENCE                 TARGETS         MINPODS   MAXPODS   REPLICAS   AGE keda-hpa-my-scaler   Deployment/simple-nginx   200/200 (avg)   1         5         5          52m

Видим, что создав сущность scaledobject контроллер создал еще и hpa, который будет управлять масштабированием приложения.
Отправим метрику со значением 100 и убедимся, что кол-во подов уменьшилось.

$ curl -X POST \   'https://monitoring.api.cloud.yandex.net/monitoring/v2/data/write?folderId=ВАШФОЛДЕР&service=custom' \   -H "Authorization: Bearer ВАШТОКЕН" \   -H "Content-Type: application/json" \   -d '{     "metrics": [         {             "name": "trigger_metric",             "labels": {                 "foo": "bar"             },             "value": 100         }     ] }'  $ kubectl get po NAME                            READY   STATUS    RESTARTS   AGE simple-nginx-7bf8c77b5b-qth7k   1/1     Running   0          4h

Отправим значение 1000 и проверим увеличение.

$ curl -X POST \   'https://monitoring.api.cloud.yandex.net/monitoring/v2/data/write?folderId=ВАШФОЛДЕР&service=custom' \   -H "Authorization: Bearer ВАШТОКЕН" \   -H "Content-Type: application/json" \   -d '{     "metrics": [         {             "name": "trigger_metric",             "labels": {                 "foo": "bar"             },             "value": 1000         }     ] }' $ kubectl get po NAME                            READY   STATUS    RESTARTS   AGE simple-nginx-7bf8c77b5b-gb2ft   1/1     Running   0          44s simple-nginx-7bf8c77b5b-j5df4   1/1     Running   0          44s simple-nginx-7bf8c77b5b-jgfd8   1/1     Running   0          44s simple-nginx-7bf8c77b5b-nhmwb   1/1     Running   0          29s simple-nginx-7bf8c77b5b-qth7k   1/1     Running   0          4h1m

В описании hpa при изменении метрик видим события вида:

Normal   SuccessfulRescale             11m                    horizontal-pod-autoscaler  New size: 1; reason: All metrics below target Normal   SuccessfulRescale             2m50s (x2 over 63m)    horizontal-pod-autoscaler  New size: 4; reason: external metric s0-metric-api-trigger_metric{foo="bar"}(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: my-scaler,},MatchExpressions:[]LabelSelectorRequirement{},}) above target

Работает!

Выводы

Думаю, все уже поняли, что в данной интеграции вместо Yandex Monitoring может быть любой http-эндпоинт, который будет опрашиваться scaledobject с заданной периодичностью. Главное, чтобы метрики были в нужном формате: yaml, json, prometheus или xml. Это дает неограниченное количество интеграций масштабирования всего и вся. Например, приложение может отдавать метрику по http, hpa будет принимать решение о масштабировании.
При этом нам не нужно хранить метрику! Достаточно её оперативно и регулярно отдавать по http, чтобы контроллер принял решение о количестве запущенных подов.


ссылка на оригинал статьи https://habr.com/ru/articles/852860/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *