Kubernetes 1.23: HPA v2 в GA и KEDA для event-driven autoscaling
Kubernetes 1.23 стабилизировал HPA v2 с custom metrics и ephemeral containers. Документируем настройку KEDA для autoscaling по очередям и внешним метрикам.
Kubernetes 1.23 выходит с HPA v2 GA, ephemeral containers stable и объявляет FlexVolume deprecated
Kubernetes 1.23 выходит в декабре - RC уже доступен, и главное в нём - это не очередной deprecated API, а, наоборот, два давно ожидаемых перевода в stable. HPA v2 с поддержкой custom и external metrics наконец-то GA. Ephemeral containers - тоже stable. FlexVolume объявлен deprecated в пользу CSI, но это отдельная история, которую мы пока трогать не будем.
Нас интересует HPA v2, потому что мы уже несколько месяцев работаем с KEDA - и теперь под ней наконец стабильный API.
Что было не так с HPA v1
HPA v1 умеет масштабировать по CPU и памяти. Это рабочий минимум, но у большинства реальных нагрузок узкое место - не CPU. Worker'ы, обрабатывающие очереди, должны масштабироваться по глубине очереди. API-сервисы - по latency или RPS. Batch-джобы - по количеству задач в очереди.
HPA v2beta1 появился ещё в 1.6 и умеет в custom metrics через Metrics API. Но beta - это beta: API мог поменяться, и менялся. HPA v2beta2 вышел в 1.12. И вот только в 1.23 всё это переходит в autoscaling/v2 без beta-суффикса.
Для нас это означает одно: конфиги, которые мы писали как autoscaling/v2beta2, теперь можно переписать в autoscaling/v2, и это не временный хак, а нормальный API.
KEDA: зачем он нужен рядом с HPA
KEDA (Kubernetes Event-Driven Autoscaling) - это не замена HPA, а расширение над ним. Он реализует интерфейс External Metrics API, который HPA умеет читать с 1.10. KEDA переводит метрики из конкретных источников - RabbitMQ, Kafka, Redis, Azure Service Bus, Prometheus - в числа, которые HPA умеет потреблять.
Без KEDA для custom metrics нужно самостоятельно писать или поднимать Prometheus Adapter, настраивать правила для каждой метрики, держать конфиги в синхронизации. KEDA делает это через ScaledObject - один ресурс, где описываешь источник и параметры масштабирования.
У нас клиент с RabbitMQ-воркерами. Несколько очередей, разные приоритеты. До KEDA масштабирование было ручным: дежурный смотрел на графики в Grafana и менял replicas руками. Это работало, пока нагрузка была предсказуемой. Потом перестало.
Установка KEDA
KEDA ставится через Helm - это самый удобный путь:
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda \
--namespace keda \
--create-namespace \
--version 2.4.0
После установки в кластере появляется несколько CRD: ScaledObject, ScaledJob, TriggerAuthentication, ClusterTriggerAuthentication. И два деплоя: оператор и metrics-сервер, который регистрируется как external metrics API.
Проверить регистрацию:
kubectl get apiservice v1beta1.external.metrics.k8s.io
# NAME SERVICE AVAILABLE AGE
# v1beta1.external.metrics.k8s.io keda/keda-operator-metrics-apiserver True 2m
Если AVAILABLE=True - HPA видит KEDA как источник метрик.
ScaledObject для RabbitMQ
Базовый пример для очереди RabbitMQ - масштабирование по глубине очереди:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: worker-scaledobject
namespace: production
spec:
scaleTargetRef:
name: worker-deployment
minReplicaCount: 1
maxReplicaCount: 20
cooldownPeriod: 60
triggers:
- type: rabbitmq
metadata:
host: amqp://rabbitmq.production.svc.cluster.local:5672
queueName: tasks-high-priority
mode: QueueLength
value: "10"
authenticationRef:
name: rabbitmq-trigger-auth
value: "10" - это целевое количество сообщений на один pod. Если в очереди 100 сообщений, HPA выставит 10 реплик. Если 5 - одна реплика (minReplicaCount).
Credentials вынесены в TriggerAuthentication:
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: rabbitmq-trigger-auth
namespace: production
spec:
secretTargetRef:
- parameter: host
name: rabbitmq-secret
key: connection-string
KEDA создаёт под собой обычный HPA-объект - его видно через kubectl get hpa. Это значит, что поведение стандартное: cooldown, stabilization window, все механизмы HPA работают.
Несколько очередей - несколько триггеров
Реальный случай: три очереди с разными приоритетами. KEDA поддерживает несколько триггеров в одном ScaledObject - масштабирование происходит по максимальному значению среди всех:
triggers:
- type: rabbitmq
metadata:
queueName: tasks-high-priority
mode: QueueLength
value: "5"
authenticationRef:
name: rabbitmq-trigger-auth
- type: rabbitmq
metadata:
queueName: tasks-normal
mode: QueueLength
value: "20"
authenticationRef:
name: rabbitmq-trigger-auth
Если в high-priority 50 сообщений (нужно 10 реплик) и в normal 40 (нужно 2 реплики) - получим 10. Это работает так, как ожидаешь.
Что с ephemeral containers
Ephemeral containers - это debug-контейнеры, которые можно запустить в существующем pod без его рестарта. Использование простое:
kubectl debug -it pod/worker-abc123 \
--image=busybox \
--target=worker \
-- sh
До stable это работало только с включённым feature gate EphemeralContainers. Теперь - по умолчанию. Для диагностики production-подов без netcat и curl в основном образе - очень удобно. Особенно если образ минимальный (distroless или scratch).
Практические наблюдения после недели с RC 1.23
Обновление манифестов. autoscaling/v2beta2 продолжает работать в 1.23 - API не удалён, только deprecated. Но мы уже начали переписывать на autoscaling/v2. Делать это заранее проще, чем в спешке перед следующим апгрейдом.
KEDA и HPA одновременно. Нельзя иметь и ScaledObject, и отдельный HPA на один Deployment - KEDA владеет HPA-объектом и перезаписывает его. Если такая конфигурация была - нужно убрать ручной HPA до применения ScaledObject.
Scale to zero. KEDA умеет уменьшать replicas до 0 при пустой очереди. Для воркеров это полезно. Для API-сервисов - осторожно: первый запрос будет ждать, пока pod поднимется. У нас пока minReplicaCount: 1 везде, где есть внешний трафик.
Результат первой недели - ручной мониторинг очередей и корректировка реплик ушли из дежурства. Это само по себе достаточный аргумент продолжать.
- Kubernetes 1.22: Ingress в GA и прощание с PodSecurityPolicy · 5 августа 2021
- Helm 3.7 + Harbor OCI: charts и образы в одном registry · 18 октября 2021