Автоскейлінг додатків Kubernetes за допомогою Prometheus та KEDA

Автоскейлінг додатків Kubernetes за допомогою Prometheus та KEDABalloon Man by Cimuanos

Масштабованість - ключова вимога для хмарних програм. З Kubernetes масштабувати програму так само просто, як і збільшити кількість реплік для відповідного розгортання або ReplicaSet - Але це ручний процес.

Kubernetes дозволяє автоматично масштабувати програми (тобто Pod у розгортанні або ReplicaSet) декларативним чином із використанням специфікації Horizontal Pod Autoscaler. За умовчанням критерій для автоматичного масштабування - метрики використання CPU (метрики ресурсів), але можна інтегрувати метрики і метрики, що надаються ззовні.

Команда Kubernetes aaS від Mail.ru переклала статтю про те, як використовувати зовнішні метрики для автоматичного масштабування програми Kubernetes. Щоб показати, як усе працює, автор використовує метрики запитів HTTP-доступу, вони збираються за допомогою Prometheus.

Замість горизонтального автомасштабування подів застосовується Kubernetes Event Driven Autoscaling (KEDA) - оператор Kubernetes з відкритим вихідним кодом. Він спочатку інтегрується з Horizontal Pod Autoscaler, щоб забезпечити плавне автомасштабування (у тому числі до/від нуля) для керованих подіями робочих навантажень. Код доступний на GitHub.

Короткий огляд роботи системи

Автоскейлінг додатків Kubernetes за допомогою Prometheus та KEDA

На схемі - короткий опис того, як усе працює:

  1. Програма надає метрики кількості звернень до HTTP у форматі Prometheus.
  2. Prometheus налаштований на збір цих показників.
  3. Скейлер Prometheus у KEDA налаштований на автоматичне масштабування програми на основі кількості звернень до HTTP.

Тепер докладно розповім про кожний елемент.

KEDA та Prometheus

Prometheus — набір інструментів для моніторингу та оповіщення систем з відкритим вихідним кодом, частина Фонд хмарних нативних обчислень. Збирає метрики з різних джерел та зберігає у вигляді даних часових рядів. Для візуалізації даних можна використовувати Grafana або інші інструменти візуалізації, які працюють з API Kubernetes.

KEDA підтримує концепцію скейлера – він діє як міст між KEDA та зовнішньою системою. Реалізація скейлера специфічна кожної цільової системи і витягує з неї дані. Потім KEDA використовує їх для керування автоматичним масштабуванням.

Скейлери підтримують кілька джерел даних, наприклад, Kafka, Redis, Prometheus. Тобто KEDA можна застосовувати для автоматичного масштабування розгортань Kubernetes, використовуючи як критерії метрики Prometheus.

Тестовий додаток

Тестовий Golang-додаток надає доступ по HTTP і виконує дві важливі функції:

  1. Використовує клієнтську бібліотеку Prometheus Go для інструментування програми та надання метрики http_requests, що містить лічильник звернень. Кінцева точка, за якою доступні метрики Prometheus, розташована за URI /metrics.
    var httpRequestsCounter = promauto.NewCounter(prometheus.CounterOpts{
           Name: "http_requests",
           Help: "number of http requests",
       })
    
  2. У відповідь на запит GET додаток збільшує значення ключа (access_count) у Redis. Це простий спосіб виконати роботу як частину обробника HTTP, а також перевірити метрики Prometheus. Значення метрики має бути таким самим, як значення access_count у Redis.
    func main() {
           http.Handle("/metrics", promhttp.Handler())
           http.HandleFunc("/test", func(w http.ResponseWriter, r 
    *http.Request) {
               defer httpRequestsCounter.Inc()
               count, err := client.Incr(redisCounterName).Result()
               if err != nil {
                   fmt.Println("Unable to increment redis counter", err)
                   os.Exit(1)
               }
               resp := "Accessed on " + time.Now().String() + "nAccess count " + strconv.Itoa(int(count))
               w.Write([]byte(resp))
           })
           http.ListenAndServe(":8080", nil)
       }
    

Програма розгортається в Kubernetes через Deployment. Також створюється служба ClusterIPВона дозволяє серверу Prometheus отримувати метрики програми.

Ось маніфест розгортання для програми.

Сервер Prometheus

Маніфест розгортання Prometheus складається з:

  • ConfigMap - Для передачі конфіга Prometheus;
  • Deployment - Для розгортання Prometheus в Kubernetes-кластері;
  • ClusterIP - Сервіс для доступу до UI Prometheus;
  • ClusterRole, ClusterRoleBinding и ServiceAccount - Для роботи автовизначення сервісів у Kubernetes (Auto-discovery).

Ось маніфест для запуску Prometheus.

KEDA Prometheus ScaledObject

Скейлер діє як міст між KEDA та зовнішньою системою, з якої потрібно отримувати метрики. ScaledObject — ресурс, що налаштовується, його необхідно розгорнути для синхронізації розгортання з джерелом подій, в даному випадку з Prometheus.

ScaledObject містить інформацію про масштабування розгортання, метадані про джерело події (наприклад, секрети підключення, ім'я черги), інтервал опитування, період відновлення та інші дані. Він призводить до відповідного ресурсу автомасштабування (визначення HPA) для масштабування розгортання.

Коли об'єкт ScaledObject видаляється, відповідне визначення HPA очищується.

Ось визначення ScaledObject для нашого прикладу, у ньому використовується скейлер Prometheus:

apiVersion: keda.k8s.io/v1alpha1
kind: ScaledObject
metadata:
 name: prometheus-scaledobject
 namespace: default
 labels:
   deploymentName: go-prom-app
spec:
 scaleTargetRef:
   deploymentName: go-prom-app
 pollingInterval: 15
 cooldownPeriod:  30
 minReplicaCount: 1
 maxReplicaCount: 10
 triggers:
 - type: prometheus
   metadata:
     serverAddress: 
http://prometheus-service.default.svc.cluster.local:9090
     metricName: access_frequency
     threshold: '3'
     query: sum(rate(http_requests[2m]))

Врахуйте такі моменти:

  1. Він вказує на Deployment з ім'ям go-prom-app.
  2. Тип тригера - Prometheus. Адреса сервера Prometheus згадується разом з ім'ям метрики, граничним значенням і запитом PromQLякий буде використовуватися. Запит PromQL sum(rate(http_requests[2m])).
  3. Згідно з pollingInterval, KEDA запитує мету у Prometheus кожні п'ятнадцять секунд. Підтримується щонайменше один під (minReplicaCount), а максимальна кількість подів не перевищує maxReplicaCount (У даному прикладі - десять).

Можна встановити minReplicaCount рівним нулю. У цьому випадку KEDA активує розгортання з нуля до одиниці, а потім надає HPA для подальшого автоматичного масштабування. Можливий зворотний порядок, тобто масштабування від одиниці до нуля. У прикладі ми не вибрали нуль, оскільки це HTTP-сервіс, а не система на запит.

Магія всередині автомасштабування

Порогове значення використовують як тригер для масштабування розгортання. У нашому прикладі запит PromQL sum(rate (http_requests [2m])) повертає агреговане значення швидкості HTTP-запитів (кількість запитів за секунду), її вимірюють протягом останніх двох хвилин.

Оскільки граничне значення дорівнює трьом, значить, буде один під, поки значення sum(rate (http_requests [2m])) менше трьох. Якщо значення зростає, додається додатковий під кожен раз, коли sum(rate (http_requests [2m])) збільшується на три. Наприклад, якщо значення від 12 до 14, то кількість подів – чотири.

Тепер спробуймо налаштувати!

Попереднє налаштування

Все, що вам потрібно – кластер Kubernetes та налаштована утиліта kubectl. У цьому прикладі використовується кластер minikubeале ви можете взяти будь-який інший. Для встановлення кластера є керівництво.

Встановити останню версію на Mac:

curl -Lo minikube 
https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 
&& chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

Встановіть кубектл, щоб отримати доступ до кластера Kubernetes

Поставити останню версію на Mac:

curl -LO 
"https://storage.googleapis.com/kubernetes-release/release/$(curl -s
https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version

Установка KEDA

Ви можете розгорнути KEDA декількома способами, вони перераховані в документації. Я використовую монолітний YAML:

kubectl apply -f
https://raw.githubusercontent.com/kedacore/keda/master/deploy/KedaScaleController.yaml

KEDA та її компоненти встановлюються у простір імен keda. Команда для перевірки:

kubectl get pods -n keda

Дочекайтесь, коли під KEDA Operator стартує - перейде в Running State. І після цього продовжуйте.

Установка Redis за допомогою Helm

Якщо у вас не встановлено Helm, скористайтесь цим керівництвом. Команда для встановлення на Mac:

brew install kubernetes-helm
helm init --history-max 200

helm init ініціалізує локальний інтерфейс командного рядка, а також встановлює Tiller в кластер Kubernetes.

kubectl get pods -n kube-system | grep tiller

Дочекайтеся переходу Tiller у стан Running.

Примітка перекладача: Автор використовує Helm@2, який вимагає встановлення серверного компонента Tiller. Зараз актуальним є Helm@3, для нього серверна частина не потрібна.

Після встановлення Helm для запуску Redis достатньо однієї команди:

helm install --name redis-server --set cluster.enabled=false --set 
usePassword=false stable/redis

Переконатись, що Redis успішно запустився:

kubectl get pods/redis-server-master-0

Дочекайтеся, коли під Redis перейде у стан Running.

Розгортання програми

Команда для розгортання:

kubectl apply -f go-app.yaml

//output
deployment.apps/go-prom-app created
service/go-prom-app-service created

Перевірити, що все запустилося:

kubectl get pods -l=app=go-prom-app

Дочекайтеся переходу Redis у стан Running.

Розгортання сервера Prometheus

Маніфест Prometheus використовує Kubernetes Service Discovery для Prometheus. Він дозволяє динамічно виявляти поди програми на основі мітки служби.

kubernetes_sd_configs:
   - role: service
   relabel_configs:
   - source_labels: [__meta_kubernetes_service_label_run]
     regex: go-prom-app-service
     action: keep

Для розгортання:

kubectl apply -f prometheus.yaml

//output
clusterrole.rbac.authorization.k8s.io/prometheus created
serviceaccount/default configured
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
configmap/prom-conf created
deployment.extensions/prometheus-deployment created
service/prometheus-service created

Перевірити, що все запустилося:

kubectl get pods -l=app=prometheus-server

Дочекайтесь, поки під Prometheus перейде в стан Running.

Використовуйте kubectl port-forward для доступу до інтерфейсу користувача Prometheus (або серверу API) за адресою http://localhost:9090.

kubectl port-forward service/prometheus-service 9090

Розгортання конфігурації автомасштабування KEDA

Команда для створення ScaledObject:

kubectl apply -f keda-prometheus-scaledobject.yaml

Перевірте логі оператора KEDA:

KEDA_POD_NAME=$(kubectl get pods -n keda 
-o=jsonpath='{.items[0].metadata.name}')
kubectl logs $KEDA_POD_NAME -n keda

Результат виглядає приблизно так:

time="2019-10-15T09:38:28Z" level=info msg="Watching ScaledObject:
default/prometheus-scaledobject"
time="2019-10-15T09:38:28Z" level=info msg="Created HPA with 
namespace default and name keda-hpa-go-prom-app"

Перевірте програму. Повинен бути запущений один екземпляр, оскільки minReplicaCount одно 1:

kubectl get pods -l=app=go-prom-app

Перевірте, що ресурс HPA успішно створено:

kubectl get hpa

Ви повинні побачити щось на кшталт:

NAME                   REFERENCE                TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-go-prom-app   Deployment/go-prom-app   0/3 (avg)   1         10        1          45s

Перевірка працездатності: доступ до програми

Щоб отримати доступ до кінцевої точки REST нашої програми, запустіть:

kubectl port-forward service/go-prom-app-service 8080

Тепер ви можете отримати доступ до програми Go, використовуючи адресу http://localhost:8080. Для цього виконайте команду:

curl http://localhost:8080/test

Результат виглядає приблизно так:

Accessed on 2019-10-21 11:29:10.560385986 +0000 UTC 
m=+406004.817901246
Access count 1

На цьому етапі також перевірте Redis. Ви побачите, що ключ access_count збільшено до 1:

kubectl exec -it redis-server-master-0 -- redis-cli get access_count
//output
"1"

Переконайтеся, що значення метрики http_requests таке ж:

curl http://localhost:8080/metrics | grep http_requests
//output
# HELP http_requests number of http requests
# TYPE http_requests counter
http_requests 1

Створення навантаження

Ми будемо використовувати агов - Утиліту для генерації навантаження:

curl -o hey https://storage.googleapis.com/hey-release/hey_darwin_amd64 
&& chmod a+x hey

Ви можете також завантажити утиліту для Linux або Windows.

Запустіть її:

./hey http://localhost:8080/test

За умовчанням утиліта надсилає 200 запитів. Ви можете переконатись у цьому, використовуючи метрики Prometheus, а також Redis.

curl http://localhost:8080/metrics | grep http_requests
//output
# HELP http_requests number of http requests
# TYPE http_requests counter
http_requests 201
kubectl exec -it redis-server-master-0 -- redis-cli get access_count
//output
201

Підтвердьте значення фактичної метрики (повернутої запитом PromQL):

curl -g 
'http://localhost:9090/api/v1/query?query=sum(rate(http_requests[2m]))'
//output
{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1571734214.228,"1.686057971014493"]}]}}

У цьому випадку фактичний результат дорівнює 1,686057971014493 і відображається у полі value. Цього недостатньо для масштабування, оскільки встановлений нами поріг дорівнює 3.

Більше навантаження!

У новому терміналі слідкуйте за кількістю подів програми:

kubectl get pods -l=app=go-prom-app -w

Давайте збільшимо навантаження за допомогою команди:

./hey -n 2000 http://localhost:8080/test

Через деякий час ви побачите, що HPA масштабує розгортання та запускає нові поди. Перевірте HPA, щоб переконатися в цьому:

kubectl get hpa
NAME                   REFERENCE                TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-go-prom-app   Deployment/go-prom-app   1830m/3 (avg)   1         10        6          4m22s

Якщо навантаження непостійне, розгортання зменшиться до точки, коли працює тільки один під. Якщо хочете перевірити фактичну метрику (повернуту запитом PromQL), використовуйте команду:

curl -g 
'http://localhost:9090/api/v1/query?query=sum(rate(http_requests[2m]))'

очищення

//Delete KEDA
kubectl delete namespace keda
//Delete the app, Prometheus server and KEDA scaled object
kubectl delete -f .
//Delete Redis
helm del --purge redis-server

Висновок

KEDA дозволяє автоматично масштабувати ваші розгортання Kubernetes (до/від нуля) на основі даних із зовнішніх метрик. Наприклад, на основі метрик Prometheus, довжини черги в Redis, затримки споживача у темі Kafka.

KEDA виконує інтеграцію із зовнішнім джерелом, а також надає його метрики через Metrics Server для Horizontal Pod Autoscaler.

Успіхів!

Що ще почитати:

  1. Найкращі практики та рекомендації для запуску контейнерів та Kubernetes у виробничих середовищах.
  2. 90+ корисних інструментів для Kubernetes: розгортання, керування, моніторинг, безпека та не тільки.
  3. Наш канал Навколо Kubernetes у Телеграмі.

Джерело: habr.com

Додати коментар або відгук