🐳 Раздел 14 · Вопрос #15

Что такое 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:

  1. В кластере должен быть установлен и запущен Metrics Server.
  2. В манифесте пода ОБЯЗАНЫ быть заданы 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 наблюдается опасный феномен:

  1. Трафик вырос $\to$ HPA добавляет 2 новых пода.
  2. Новые JVM поды запускаются. На фазе старта компилятор C2 JIT начинает агрессивно оптимизировать методы, вызывая кратковременный скачок CPU до 100% на 30–45 секунд.
  3. HPA опрашивает Metrics Server, видит 100% CPU на новых подах и считает, что нагрузка всё ещё запредельная.
  4. 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). Три главные причины:

  1. Отсутствие resources.requests: в шаблоне контейнера Deployment не заданы requests.cpu. Без них HPA физически не может вычислить процент использования.
  2. Metrics Server не установлен или упал: в кластере отсутствует или аварийно завершился под metrics-server (или он запущен без флага --kubelet-insecure-tls в тестовых кластерах).
  3. Холодный старт подов: поды только что запустились, и 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?

Ответ: Возникнет конфликт императивного и декларативного управления:

  1. Команда kubectl scale принудительно обновит поле spec.replicas: 5 в Deployment.
  2. Однако через 15 секунд проснется цикл согласования HPA (Reconciliation Loop).
  3. Контроллер 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.

Связанные вопросы