← Back to notes

Autoscaling: HPA, VPA,
KEDA, Cluster Autoscaler


Масштабирование в Kubernetes делится на два независимых уровня: масштабирование workload (сколько Pod и с какими ресурсами) и масштабирование инфраструктуры (сколько нод). HPA и KEDA меняют число реплик, VPA — requests/limits внутри Pod, Cluster Autoscaler и Karpenter — число нод. Эти механизмы дополняют друг друга и работают одновременно.

HorizontalPodAutoscaler (HPA)

HPA автоматически меняет число реплик Deployment, StatefulSet или ReplicaSet по наблюдаемым метрикам. Актуальный API — autoscaling/v2.

[source: kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/]

Алгоритм

Контроллер работает в цикле (по умолчанию каждые 15 секунд) и вычисляет желаемое число реплик по формуле:

desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)]

Например, при 3 репликах и текущем среднем CPU 200m против целевого 100m: ceil(3 * 200/100) = 6 реплик. Если отношение метрик попадает в tolerance (по умолчанию 0.1, то есть ±10%) — HPA не масштабирует, чтобы избежать дёрганья.

[source: kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/]

Важные детали работы:

  • Unready Pod исключаются из расчёта метрик.
  • При отсутствии метрик HPA считает консервативно: 100% потребления для scale-down, 0% для scale-up.
  • HPA не применяется к DaemonSet и другим немасштабируемым объектам.
  • При нескольких метриках HPA выбирает ту, что требует наибольшего числа реплик.

Метрики и связь с requests

autoscaling/v2 поддерживает пять типов метрик:

ТипЧто измеряет
ResourceCPU/memory Pod, как utilization (% от requests) или absolute value
ContainerResourceCPU/memory конкретного контейнера в Pod
PodsКастомная метрика в среднем по всем Pod (например, RPS)
ObjectМетрика одного объекта в кластере (например, Ingress)
ExternalМетрика из внешней системы (очередь, брокер)

При target.type: Utilization HPA считает процент относительно requests контейнера. Без заданных CPU requests utilization-таргет по CPU работать не будет — HPA не с чем сравнивать. Это прямая связь с 13: Resource Management: корректные requests — предусловие для HPA.

[source: kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/]

Для Resource-метрик (CPU/memory) в кластере обязателен metrics-server — он агрегирует потребление Pod и отдаёт его через metrics.k8s.io API.

[source: kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/]

Поле behavior

Поле behavior управляет скоростью и стабильностью масштабирования отдельно для scaleUp и scaleDown:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300   # окно стабилизации перед scale-down
      policies:
        - type: Percent
          value: 50                     # не более 50% реплик за period
          periodSeconds: 60
        - type: Pods
          value: 2                      # не более 2 Pod за period
          periodSeconds: 60
      selectPolicy: Min                 # берём самую консервативную политику
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 30
      selectPolicy: Max
  • stabilizationWindowSeconds — HPA смотрит на максимум желаемых реплик за окно и не опускается ниже; для scaleDown по умолчанию 300s, для scaleUp — 0s.
  • policies типа Pods (абсолютное число) и Percent (доля) ограничивают шаг масштабирования за periodSeconds.
  • selectPolicy: Max, Min или Disabled (например, scaleDown.selectPolicy: Disabled полностью запрещает уменьшение).

[source: kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/]

VerticalPodAutoscaler (VPA)

VPA подбирает requests/limits контейнеров по историческому и текущему потреблению. Устанавливается отдельно (не входит в ядро Kubernetes).

[source: github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler]

Компоненты

КомпонентРоль
RecommenderАнализирует потребление Pod и вычисляет рекомендованные requests/limits
UpdaterПрименяет рекомендации к работающим Pod (в зависимости от режима)
Admission ControllerПерезаписывает requests/limits при создании Pod

[source: github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler]

Режимы (updateMode)

Значения updatePolicy.updateMode из API VPA:

РежимПоведение
OffVPA не меняет ресурсы, только пишет рекомендации в объект VPA (dry-run)
InitialРесурсы назначаются только при создании Pod, дальше не меняются
RecreateРесурсы назначаются при создании и обновляются в течение жизни Pod через удаление и пересоздание
AutoЛюбой доступный метод обновления; помечен как deprecated и сейчас эквивалентен Recreate
InPlaceOrRecreateПытается применить in-place, при неудаче откатывается на Recreate
InPlaceТолько eviction-free in-place resize без пересоздания Pod; alpha (VPA v1.7.0+, требует K8s 1.33+)

[source: github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go]

Режим InPlaceOrRecreate использует in-place resize контейнеров без пересоздания Pod. По документации VPA он прошёл путь alpha (VPA v1.4.0) → beta (VPA v1.5.0) → GA (VPA v1.6.0); feature gate InPlaceOrRecreate включён по умолчанию с v1.5.0 и удалён в v1.7.0. Опирается на in-place pod resize Kubernetes.

[source: github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/docs/features.md]

Сам in-place pod resize (InPlacePodVerticalScaling) в Kubernetes — GA с версии 1.35 (см. 13: Resource Management).

[source: kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/]

HPA и VPA вместе

VPA нельзя использовать вместе с HPA по одной и той же resource-метрике (CPU или memory): оба будут реагировать на одно потребление и войдут в конфликт — HPA добавляет реплики, VPA одновременно меняет их requests, ломая расчёт utilization. Официальная рекомендация: комбинировать их только по разным сигналам, например VPA по memory + HPA по CPU, либо HPA по custom/external метрикам.

[source: github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/docs/known-limitations.md]

KEDA (Kubernetes Event-Driven Autoscaling)

KEDA расширяет HPA до event-driven масштабирования по внешним источникам событий и добавляет scale-to-zero. Это CNCF-проект, устанавливается отдельно.

[source: keda.sh/docs/latest/concepts/]

Архитектура

КомпонентРоль
keda-operatorСледит за ресурсами KEDA (ScaledObject) и управляет полным жизненным циклом HPA; отвечает за переходы 0↔1 реплики
keda-metrics-apiserverОтдаёт внешние метрики (Kafka, RabbitMQ, SQS и т.д.) в HPA через Kubernetes API как external metrics
keda-admission-webhooksВалидируют ресурсы KEDA (например, ScaledObject) в момент применения, отлавливая ошибки конфигурации

Ключевая деталь: KEDA не заменяет HPA, а создаёт его под капотом. Operator обрабатывает переходы 0→1 и 1→0, а масштабирование 1→N делает штатный HPA, потребляя external-метрики из keda-metrics-apiserver. Поэтому весь механизм behavior/policies HPA доступен и с KEDA.

[source: keda.sh/docs/latest/concepts/]

ScaledObject vs ScaledJob

KEDA предоставляет CRD ScaledObject, ScaledJob и TriggerAuthentication.

РесурсНазначение
ScaledObjectСвязывает Deployment/StatefulSet с источником событий и масштабирует число реплик работающих Pod
ScaledJobСоздаёт новые Kubernetes Job в ответ на события (batch-обработка)

[source: keda.sh/docs/latest/concepts/]

Scale-to-zero доступен для event-триггеров: при отсутствии событий workload сворачивается в 0 реплик. Важное ограничение — scale-to-zero не работает с CPU/memory-триггерами: без запущенных Pod метрики просто нечем наблюдать.

[source: keda.sh/docs/latest/concepts/]

Пример ScaledObject

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: consumer-scaler
spec:
  scaleTargetRef:
    name: consumer          # имя Deployment
  minReplicaCount: 0        # scale-to-zero
  maxReplicaCount: 30
  cooldownPeriod: 300       # ждать перед сворачиванием в 0
  triggers:
    - type: kafka
      metadata:
        bootstrapServers: kafka:9092
        consumerGroup: my-group
        topic: events
        lagThreshold: "100"  # реплика на каждые 100 сообщений lag

Из популярных scalers/triggers: Apache Kafka (по consumer lag), RabbitMQ (длина очереди), Prometheus (любой PromQL-запрос), AWS SQS (глубина очереди), Cron (масштабирование по расписанию), плюс более 70 других источников.

[source: keda.sh/docs/latest/concepts/]

Масштабирование нод: Cluster Autoscaler vs Karpenter

HPA/VPA/KEDA меняют Pod, но если в кластере физически нет места — новые Pod остаются Pending. Масштабирование нод решает это: добавляет ноды под неразмещаемые Pod и убирает недогруженные для экономии.

[source: kubernetes.io/docs/concepts/cluster-administration/node-autoscaling/]

АспектCluster AutoscalerKarpenter
МодельУправляет заранее заданными node group (гомогенными)Провижинит отдельные ноды без node group
ПровижинингДобавляет ноды в подходящую группу под pending PodJust-in-time, right-sized ноды под конкретные Pod
ОбластьТолько autoscalingПолный жизненный цикл ноды: scaling + refresh + upgrade
Auto-provisioningНетЕсть (выбор типа ноды по ограничениям NodePool)

[source: kubernetes.io/docs/concepts/cluster-administration/node-autoscaling/]

Cluster Autoscaler масштабирует существующие node group (например, AWS Auto Scaling Group) вверх/вниз по числу pending Pod. Karpenter подбирает оптимальный тип инстанса под требования Pod без предварительной настройки групп и умеет консолидировать/обновлять ноды.

[source: kubernetes.io/docs/concepts/cluster-administration/node-autoscaling/]

Сравнение

МеханизмЧто масштабируетПо чемуScale-to-zero
HPAЧисло реплик PodCPU/memory (% от requests), custom, externalНет
VPArequests/limits внутри PodИсторическое потребление CPU/memoryНет
KEDAЧисло реплик Pod (создаёт HPA)События: очереди, брокеры, Prometheus, cronДа (event-триггеры)
Cluster Autoscaler / KarpenterЧисло нодPending Pod / утилизация нодНоды — да (до 0 в группе/пуле)

Типичные ошибки

HPA без requests. При target.type: Utilization по CPU без заданных CPU requests HPA не может посчитать процент и не масштабирует. Всегда задавай requests.

HPA и VPA по одной метрике. Конфликт: разноси по разным сигналам (VPA memory + HPA CPU) или используй HPA по custom/external метрикам.

Отсутствует metrics-server. Без него Resource-метрики недоступны, HPA показывает unknown и не работает.

Флаппинг реплик. Резкие циклы scale-up/down. Лечится через behavior.scaleDown.stabilizationWindowSeconds и policies, ограничивающие шаг.

KEDA scale-to-zero на CPU/memory. Не сработает: без Pod нет метрик. Scale-to-zero — только для event-триггеров.

Autoscaling Pod без autoscaling нод. HPA/KEDA наращивают реплики, но они висят в Pending — нет узлов. Нужен Cluster Autoscaler или Karpenter в паре.

Игнор PDB при scale-down нод. Агрессивная консолидация нод может нарушить доступность — см. 27: PDB и обновления.


27: PDB и обновления

К оглавлению курса

Autoscaling: HPA, VPA, KEDA, Cluster Autoscaler | Aleksandr Suprun