HPA для Application

Уровень: expert ~55 мин Практика: Umami (продолжение) (MIT)

Что нужно знать перед уроком

  • M10.02 — Кастомные дашборды и алерты — нужно понимание recording rules, из которых часто строятся кастомные метрики для HPA

Что нужно знать перед уроком

M10 урок 2 — recording rules. Этот урок разбирает HorizontalPodAutoscaler — автоматическое горизонтальное масштабирование Application по метрикам, включая специфичные для Deckhouse CRD кастомных метрик.

Теория

Типы метрик в autoscaling/v2

Стандартный Kubernetes HorizontalPodAutoscaler (apiVersion: autoscaling/v2) поддерживает несколько типов источников метрик: Resource (стандартные CPU/память по запросам ресурсов контейнера), Pods (кастомная метрика, усреднённая по всем подам), Object (метрика, привязанная к конкретному объекту Kubernetes — Service, Ingress, любой другой ресурс), External (метрика из внешней системы, не привязанная к объектам кластера).

ServiceMetric/IngressMetric — CRD Deckhouse для кастомных метрик через Object

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: deckhouse.io/v1beta1
kind: ServiceMetric
metadata:
  name: rmq-queue-forum-messages
  namespace: mynamespace
spec:
  query: sum (rabbitmq_queue_messages{<<.LabelMatchers>>,queue=~"send_forum_message",vhost="/"}) by (<<.GroupBy>>)
---
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2
metadata:
  name: myhpa
  namespace: mynamespace
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myconsumer
  minReplicas: 1
  maxReplicas: 5
  metrics:
    - type: Object
      object:
        describedObject:
          apiVersion: v1
          kind: Service
          name: rmq
        metric:
          name: rmq-queue-forum-messages
        target:
          type: Value
          value: 42

Реальный пример из документации: масштабирование Deployment-воркера по числу сообщений в очереди RabbitMQ. ServiceMetric определяет PromQL-запрос, регистрируя его как метрику, привязанную к конкретному Service; <<.LabelMatchers>>/<<.GroupBy>> — специальные плейсхолдеры Deckhouse, автоматически подставляющие корректные фильтры по namespace/сервису и группировку, соответствующую конкретному объекту — их не нужно (и не следует) заполнять вручную. HorizontalPodAutoscaler затем ссылается на эту зарегистрированную метрику через type: Object, указывая describedObject (объект, к которому привязана метрика) и target (пороговое значение).

IngressMetric — аналогичный механизм для метрик Ingress

1
2
3
4
5
6
7
apiVersion: deckhouse.io/v1beta1
kind: IngressMetric
metadata:
  name: mymetric
  namespace: mynamespace
spec:
  query: sum(rate(ingress_nginx_detail_requests_total{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>) OR on() vector(0)

OR on() vector(0) в конце запроса — важная деталь: гарантирует, что запрос вернёт 0 вместо пустого результата, если метрика временно отсутствует (например, нет входящего трафика вообще) — без этого HPA может получить ошибку от адаптера метрик при полном отсутствии данных, вместо корректного нулевого значения.

Готовые метрики rps_1m/rps_5m/rps_15m — без создания CRD

prometheus-metrics-adapter предоставляет несколько готовых метрик частоты запросов (в разных временных окнах усреднения — 1, 5, 15 минут) для Ingress-объектов, доступных напрямую через type: Object без необходимости создавать собственный IngressMetric — это самый простой путь для типового сценария «масштабировать по RPS», если готовое временное окно усреднения устраивает.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
metrics:
  - type: Object
    object:
      describedObject:
        apiVersion: networking.k8s.io/v1
        kind: Ingress
        name: myingress
      metric:
        name: rps_5m
      target:
        type: AverageValue
        averageValue: 100

Настраиваемый tolerance (Kubernetes 1.35+)

До Kubernetes 1.35 HPA использовал единый глобальный tolerance 10% для всех решений о масштабировании — метрика должна была отклониться от целевого значения больше чем на 10%, чтобы HPA вообще среагировал (это защита от «дребезга» при незначительных колебаниях). Начиная с Kubernetes 1.35 (beta, включено по умолчанию) это ограничение можно настроить для конкретного ресурса через поле behavior:

1
2
3
4
5
6
spec:
  behavior:
    scaleUp:
      tolerance: 0.05 # реагировать уже на отклонение метрики от 5%, а не от 10%
    scaleDown:
      tolerance: 0.05

Это полезно для чувствительных к нагрузке компонентов (нужно масштабироваться быстрее, чем позволяет дефолтные 10%) — раньше такая точность требовала настройки на уровне всего кластера (флаг kube-controller-manager), а не отдельного HPA.

Value vs AverageValue для type: Object

target.type: Value — сравнивается с абсолютным значением метрики (например, «масштабировать, если очередь превышает 42 сообщения», независимо от текущего числа реплик). target.type: AverageValue — значение делится на текущее число реплик перед сравнением (например, «масштабировать, если RPS на одну реплику превышает 100» — растёт вместе с числом реплик, стабилизируя нагрузку на каждую отдельную реплику).

Частые ошибки и подводные камни

  • Забывать OR on() vector(0) в PromQL-запросе кастомной метрики, которая может временно возвращать пустой результат. Отсутствие этой конструкции приводит к ошибкам HPA при отсутствии данных вместо корректной обработки нулевого значения.
  • Заполнять <<.LabelMatchers>>/<<.GroupBy>> вручную конкретными значениями. Это специальные плейсхолдеры Deckhouse, автоматически подставляемые системой в контексте конкретного ServiceMetric/IngressMetric — ручное заполнение конкретными значениями сломает автоматическую привязку к объекту.
  • Путать Value и AverageValue для type: Object, приводя к неверной логике масштабирования. Value не учитывает текущее число реплик, AverageValue учитывает — выбор неверного типа приводит к некорректному поведению при масштабировании (например, недостаточно агрессивному или, наоборот, чрезмерному масштабированию).

Практика в кластере

🧩 Практика урока: Umami (продолжение) · лицензия MIT
1
2
d8 k get hpa -n course-m10-umami
d8 k describe hpa umami -n course-m10-umami | grep -A5 "Metrics:"

Проверьте, что HPA пакета Umami корректно получает значение кастомной или встроенной метрики (rps_5m для Ingress, если Umami настроен с Ingress).

Практика разработки

Добавьте в пакет Umami HorizontalPodAutoscaler, масштабирующий основной Deployment по готовой метрике rps_5m через type: Object без создания собственного IngressMetric, с minReplicas: 1/maxReplicas: 5 и target.type: AverageValue.

Шпаргалка команд урока

1
2
d8 k get servicemetric,ingressmetric -A
d8 k get hpa -A -o wide

Вопросы для самопроверки

Для чего нужны плейсхолдеры <<.LabelMatchers>>/<<.GroupBy>> в PromQL-запросе ServiceMetric/IngressMetric?

Ручное заполнение конкретными значениями сломает автоматическую привязку к объекту.

Источник: Deckhouse — Hpa

Зачем в конце PromQL-запроса IngressMetric добавляется OR on() vector(0)?

Без этого HPA может получить ошибку от адаптера метрик при полном отсутствии трафика.

Источник: Deckhouse — Scaling by metrics

Можно ли масштабировать по RPS Ingress без создания собственного IngressMetric?

Это самый простой путь для типового сценария масштабирования по RPS.

Источник: Deckhouse — Scaling by metrics

Чем target.type: AverageValue отличается от Value для type: Object?

AverageValue стабилизирует нагрузку на каждую отдельную реплику при масштабировании.

Источник: Deckhouse — Scaling by metrics

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Brendan Burns, David Oppenheimer. Designing Distributed Systems. 2018. ISBN 978-1491983645.
  • Marko Lukša. Kubernetes in Action. 2nd ed., 2022. ISBN 978-1617297618.

Связанные материалы