Масштабирование в 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 поддерживает пять типов метрик:
| Тип | Что измеряет |
|---|---|
| Resource | CPU/memory Pod, как utilization (% от requests) или absolute value |
| ContainerResource | CPU/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:
| Режим | Поведение |
|---|---|
| Off | VPA не меняет ресурсы, только пишет рекомендации в объект 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 Autoscaler | Karpenter |
|---|---|---|
| Модель | Управляет заранее заданными node group (гомогенными) | Провижинит отдельные ноды без node group |
| Провижининг | Добавляет ноды в подходящую группу под pending Pod | Just-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 | Число реплик Pod | CPU/memory (% от requests), custom, external | Нет |
| VPA | requests/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 и обновления.