🐳 Розділ 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.

Пов’язані питання