Что такое HorizontalPodAutoscaler
HPA — это администратор ресторана в пятницу вечером:
🟢 Junior Level
30-секундный ответ
HorizontalPodAutoscaler (HPA) — это встроенный контроллер Kubernetes, который автоматически регулирует количество реплик подов в Deployment или StatefulSet в зависимости от текущей нагрузки на приложение.
- Как это работает: HPA каждые 15 секунд опрашивает
Metrics Server, измеряет среднюю утилизацию ресурсов (например, загрузку процессора CPU) и сравнивает её с целевым порогом (Target). - Всплеск трафика: нагрузка на CPU выросла выше целевой $\to$ HPA увеличивает количество подов (Scale Up), распределяя нагрузку.
- Спад трафика: ночью пользователи ушли спать, CPU упал $\to$ HPA плавно уменьшает количество подов до минимума (Scale Down), экономя серверные мощности.
Наглядная аналогия из жизни
HPA — это администратор ресторана в пятницу вечером:
- Если столики переполнены и официанты бегают в мыле (загрузка CPU > 70%), администратор вызывает на смену дополнительных официантов из резерва.
- Когда к полуночи гости расходятся (загрузка CPU < 20%), лишних официантов отпускают домой, чтобы заведение не платило им зарплату за простой.
Базовый манифест HPA (API autoscaling/v2)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-service
minReplicas: 2 # Минимальная квота для High Availability
maxReplicas: 10 # Защита от переполнения бюджета
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60 # Держать среднюю загрузку CPU около 60%
[!IMPORTANT] Два фундаментальных требования для работы HPA:
- В кластере должен быть установлен и запущен
Metrics Server.- В манифесте пода ОБЯЗАНЫ быть заданы
resources.requests.cpu, так как процент загрузки вычисляется строго от значенияrequests!
🟡 Middle Level
Формула расчёта реплик и порог толерантности (Tolerance)
Контроллер HPA вычисляет необходимое число реплик по математической формуле:
\[\mathbf{DesiredReplicas} = \left\lceil \mathbf{CurrentReplicas} \times \left( \frac{\mathbf{CurrentMetricValue}}{\mathbf{TargetMetricValue}} \right) \right\rceil\]Защитный порог толерантности (10% Tolerance)
Чтобы контроллер не дергал поды туда-обратно из-за колебаний в 1–2%:
- В K8s встроен параметр
horizontal-pod-autoscaler-tolerance(по умолчанию0.1, то есть 10%). -
Если соотношение $\left \frac{\text{Current}}{\text{Target}} - 1.0 \right \le 0.1$, HPA вообще ничего не делает! - Пример: если целевой CPU = 60%, а текущий колеблется между 55% и 65%, HPA не масштабирует систему.
4 типа поддерживаемых метрик в autoscaling/v2
| Тип метрики | Источник данных | Пример использования |
|---|---|---|
Resource |
Metrics Server (cgroups) | Стандартный cpu или memory контейнера. |
Pods |
Prometheus Adapter | Метрики приложения, агрегированные по подам (например, HTTP RPS на под). |
Object |
Prometheus Adapter / K8s API | Метрика стороннего K8s объекта (глубина очереди на Ingress). |
External |
Внешние провайдеры (Datadog/CloudWatch) | Глубина очереди Amazon SQS, длина очереди RabbitMQ. |
Тонкая настройка скорости: Блок behavior
Для предотвращения эффекта «дребезга» (Flapping) настраивают окна стабилизации:
spec:
behavior:
scaleUp:
stabilizationWindowSeconds: 0 # Масштабироваться вверх немедленно
policies:
- type: Percent
value: 100 # Максимум удваивать поды за один шаг
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300 # Ждать 5 минут спада перед удалением!
policies:
- type: Pods
value: 1 # Удалять не более 1 пода раз в 60 секунд
periodSeconds: 60
🔴 Senior Level
Правило разрешения множественных метрик (Multi-Metric HPA)
Если в HPA объявлено несколько метрик (например, CPU + RPS + Latency):
metrics:
- type: Resource
resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } } # Расчёт: 4 пода
- type: Pods
pods: { metric: { name: http_requests_per_second }, target: { averageValue: "100" } } # Расчёт: 8 подов
Алгоритм выбора: HPA вычисляет количество реплик для каждой метрики независимо и выбирает МАКСИМАЛЬНОЕ значение (MAX) из всех полученных результатов. В данном примере будет установлено 8 подов.
Проблема «Ложного овершутинга» в Java (JIT Warmup Trap)
В реальных production-кластерах с Java Spring Boot наблюдается опасный феномен:
- Трафик вырос $\to$ HPA добавляет 2 новых пода.
- Новые JVM поды запускаются. На фазе старта компилятор C2 JIT начинает агрессивно оптимизировать методы, вызывая кратковременный скачок CPU до 100% на 30–45 секунд.
- HPA опрашивает Metrics Server, видит 100% CPU на новых подах и считает, что нагрузка всё ещё запредельная.
- HPA добавляет ещё 4 пода $\to$ они тоже вызывают 100% JIT-нагрузку $\to$ HPA улетает в
maxReplicas(эффект лавины). Архитектурное решение:- Настройка
startupProbeс увеличенным временем, чтобы под не считался готовым до завершения базовой инициализации. - Использование
behavior.scaleUp.stabilizationWindowSeconds: 60или политик ограничения прироста. - Переход на GraalVM Native Image или технологию CRaC (Coordinated Restore at Checkpoint) в Java 21.
- Настройка
Архитектура KEDA (Kubernetes Event-Driven Autoscaling)
Когда метрик Prometheus недостаточно, стандартом де-факто становится KEDA:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: kafka-consumer-scaler
spec:
scaleTargetRef:
name: payment-consumer
minReplicaCount: 0 # Полная поддержка Scale to Zero!
maxReplicaCount: 20
triggers:
- type: kafka
metadata:
bootstrapServers: kafka:9092
consumerGroup: payment-processors
topic: payments
lagThreshold: "100" # Добавлять под на каждые 100 сообщений лага
Под капотом KEDA автоматически создаёт нативный HPA и регистрирует свой External Metrics API сервер, скрывая сложность работы с Prometheus Adapter.
4 Tricky Questions
1. Как работает встроенный порог толерантности HPA (10% Tolerance), и почему HPA не предпринимает действий, если CPU вырос с 50% до 54% при target = 50%?
Ответ:
Для предотвращения постоянного дёрганья подов из-за незначительных колебаний нагрузки контроллер HPA использует формулу проверки толерантности:
\(\left| \frac{\text{CurrentMetricValue}}{\text{TargetMetricValue}} - 1.0 \right| \le \text{tolerance}\)
По умолчанию флаг --horizontal-pod-autoscaler-tolerance равен 0.1 (10%).
В данном случае: $54 / 50 = 1.08$.
Величина отклонения: $|1.08 - 1.0| = 0.08$ (8%), что строго меньше порога в 10% (0.1).
Поскольку отклонение не превысило порог толерантности, контроллер HPA полностью игнорирует это изменение и сохраняет текущее количество реплик неизменным.
2. Почему в выводе команды kubectl get hpa в столбце TARGETS отображается статус <unknown>/60%, и какие 3 причины вызывают это состояние?
Ответ:
Статус <unknown> означает, что контроллер HPA не может прочитать метрики утилизации подов из Kubernetes Resource Metrics API (v1beta1.metrics.k8s.io).
Три главные причины:
- Отсутствие
resources.requests: в шаблоне контейнера Deployment не заданыrequests.cpu. Без них HPA физически не может вычислить процент использования. - Metrics Server не установлен или упал: в кластере отсутствует или аварийно завершился под
metrics-server(или он запущен без флага--kubelet-insecure-tlsв тестовых кластерах). - Холодный старт подов: поды только что запустились, и Metrics Server ещё не успел собрать первый интервал агрегации (обычно требуется подождать 30–60 секунд).
3. Если в HPA задано 3 метрики: CPU (требует 4 пода), Memory (требует 6 подов) и Custom RPS (требует 8 подов), какое итоговое число реплик выставит контроллер?
Ответ:
Контроллер выставит 8 подов.
В соответствии со спецификацией Kubernetes autoscaling/v2, при объявлении нескольких метрик в блоке metrics контроллер HPA производит независимый расчёт требуемого количества реплик для каждого правила в отдельности, а затем применяет функцию max() к полученным результатам:
\(\text{Replicas} = \max(\text{Replicas}_{\text{CPU}}, \text{Replicas}_{\text{Memory}}, \text{Replicas}_{\text{RPS}}) = \max(4, 6, 8) = 8\)
Это сделано для обеспечения надёжности: система ориентируется на самый перегруженный ресурс, гарантируя соблюдение SLA.
4. В чём опасность масштабирования Deployment с помощью kubectl scale --replicas=5, если для этого же Deployment параллельно активен объект HPA?
Ответ: Возникнет конфликт императивного и декларативного управления:
- Команда
kubectl scaleпринудительно обновит полеspec.replicas: 5в Deployment. - Однако через 15 секунд проснется цикл согласования HPA (
Reconciliation Loop). - Контроллер HPA оценит текущую реальную нагрузку на поды. Если нагрузка низкая и соответствует 2 репликам, HPA мгновенно перезапишет значение
spec.replicasобратно на 2, принудительно удалив 3 только что созданных пода. Правило: при активном HPA ручное масштабирование черезkubectl scaleбессмысленно; необходимо менять границыminReplicasиmaxReplicasв самом объекте HPA.
🎯 Шпаргалка для интервью
Главное об HPA
- Суть: контроллер автоматического горизонтального масштабирования подов.
- Интервал опроса: каждые 15 секунд через Metrics API.
- Обязательные требования:
Metrics Serverв кластере иresources.requestsв манифесте пода. - Формула: $\text{Desired} = \lceil \text{Current} \times (\text{CurrentMetric} / \text{TargetMetric}) \rceil$.
- Множественные метрики: всегда выбирается
MAX()из всех расчётов. - Java Golden Rule: избегать масштабирования по памяти; масштабировать строго по CPU или RPS.
- Стабилизация (Behavior): scaleUp быстрый (0–15s), scaleDown медленный (300s).
Типы метрик HPA
| Тип | Источник | Применение |
| :— | :— | :— |
| Resource | cgroups контейнера | CPU, Memory |
| Pods | Prometheus Adapter | HTTP RPS, P99 Latency |
| Object | K8s ресурсы | Ingress connections, Queue size |
| External | Облачные API / Datadog | Kafka Lag (KEDA), AWS SQS |
Красные флаги на собеседовании (Чего говорить нельзя)
- ❌ «HPA рассчитывает процент загрузки CPU от значения resources.limits» — процент всегда считается строго от
resources.requests. - ❌ «Если для Deployment настроен HPA, я могу в любой момент смасштабировать его командой kubectl scale» — HPA через 15 секунд перезапишет число реплик обратно.
- ❌ «HPA умеет масштабировать сервис из 0 подов при поступлении трафика» — стандартный HPA не умеет Scale to Zero; для этого нужен KEDA или Knative.