Site icon IT Education Center Blog – блог навчального центру DevOps – ITEDU by NETFORCE Group

Оптимізація ресурсів у K8s: повний посібник з Autoscaling

Автомасштабування в Kubernetes — це динамічний процес автоматичного коригування обчислювальних ресурсів у кластері залежно від поточного навантаження. Його головна мета полягає у тому, щоб забезпечити безперебійну роботу застосунків під час напливу користувачів і водночас звільнити зайві потужності, коли потреба в них зникає.

Попри те, що близько 96% компаній уже перейшли на Kubernetes, середня утилізація процесора (CPU) у кластерах становить лише близько 13%. Тобто колосальний обсяг куплених потужностей просто проїдає бюджет.

Головна причина — так званий оверпровіженінг (over-provisioning), або штучне завищення лімітів:

Саме для розв’язання цих проблем і потрібна гнучка система автоматичного масштабування. 

Архітектура Kubernetes Autoscaling

У Kubernetes не існує одного універсального інструменту для масштабування, оскільки архітектура всієї платформи розділена на рівні. Повноцінна автоматизація ресурсів складається з трьох взаємопов’язаних компонентів, кожен з яких виконує своє чітке завдання.

Горизонтальне масштабування подів 

Horizontal Pod Autoscaling (HPA) — це масштабування в ширину. 

Коли навантаження зростає, Kubernetes створює нові копії (репліки) подів, щоб розподілити між ними трафік. При спаді активності юзерів — зайві копії видаляються. Це базовий вибір для вебзастосунків та мікросервісів.

Вертикальне масштабування подів 

Vertical Pod Autoscaler (VPA) — це, як ви вже догадались, масштабування вгору. 

Замість створення нових подів, система змінює розмір уже наявних — автоматично додає або зменшує їм CPU та оперативну пам’ять. Підхід незамінний для баз даних або фонових завдань, які складно розпаралелити на багато копій.

Масштабування інфраструктури 

Коли попередні інструменти намагаються запустити нові поди, а на серверах (нодах) немає вільного місця, поди зависають у статусі Pending. Інфраструктурний скейлер помічає це, автоматично додає у хмарі нові віртуальні машини, а при спаді навантаження — виводить порожні ноди з експлуатації.

Важливе правило архітектури: Масштабування навантажень (HPA/VPA) та масштабування інфраструктури повинні працювати в синергії. Автоматика на рівні застосунку створює попит на ресурси, а автоматика на рівні інфраструктури цей попит задовольняє. 

Рівень робочих навантажень 

Як ми вже з’ясували, рівень робочих навантажень відповідає за адаптацію самих застосунків під поточний потік запитів. Оскільки програми бувають різними — архітектурно та за типом споживання ресурсів — Kubernetes використовує два різні підходи, які ви вже знаєте: горизонтальний (HPA) та вертикальний (VPA).

Тепер зазирнемо під капот кожного з них.

HPA та скейлінг на основі подій 

Процес керування є безперервним циклом зворотного зв’язку (feedback loop):

  1. Збір метрик
    У кластері працює Metrics Server, який безперервно збирає дані про те, скільки ресурсів споживає кожен под.
  2. Опитування контролером
    HPA-контролер із фіксованим інтервалом (за замовчуванням — кожні 15 секунд) звертається до Metrics Server API.
  3. Обчислення та реакція
    Контролер порівнює поточні значення з цільовими (thresholds) з маніфесту. Якщо ліміт перевищено — HPA дає команду розгортанню (Deployment) створити нові копії подів.

Розбір базового YAML-маніфесту для HPA

Ось як виглядає реальна конфігурація, яка одночасно відстежує завантаження процесора та пам’яті:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-autoscale
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70

Обмеження стандартного HPA

Попри просту логіку, класичний HPA має два суттєві недоліки:

  1. Запізнення: HPA реагує на події постфактум. Поки Metrics Server збере дані, а HPA вирахує нову кількість подів, застосунок під час раптового шквального трафіку може встигнути лягти.
  2. Сліпота до бізнес-метрик: стандартний HPA знає лише про CPU та RAM. Проте навантаження на сервіс може подвоїтися через чергу завдань, а процесор залишатиметься холодним.

Щоб обійти ці ліміти, в індустрії використовують KEDA (Kubernetes Event-driven Autoscaling) — зовнішню надбудову для K8s. KEDA діє проактивно і скейлить поди на основі зовнішніх подій. Наприклад, він може підключитися до черги повідомлений (RabbitMQ чи Apache Kafka) і миттєво додати поди, якщо бачить, що в черзі накопичилося понад 100 необроблених тасок.

Крім того, KEDA вміє масштабувати робочі навантаження до нуля. Якщо черга порожня, він повністю гасить поди застосунку, економлячи бюджет, а при появі нової задачі — миттєво піднімає їх назад.

VPA та конфлікти ресурсів 

Якщо HPA плодив копії, то VPA діє вглиб — він не чіпає кількість подів, а автоматично змінює розмір (requests та limits CPU/RAM) всередині вже наявних контейнерів. Це рятує, коли застосунок архітектурно є монолітом або базою даних, яку не можна просто розмножити «в ширину».

Анатомія VPA

Для керування цим процесом архітектура VPA використовує три окремі службові компоненти:

  1. VPA Recommender: аналізує поточне споживання ресурсів та історію поведінки контейнера, розраховуючи для нього оптимальні значення CPU та RAM.
  2. VPA Updater: стежить за рекомендаціями. Якщо реальні потреби подів сильно відрізняються від того, що пропонує Recommender, він дає команду на видалення пода, щоб той перезапустився з новими параметрами.
  3. VPA Admission Controller: спеціальний вебхук, який перехоплює под у момент його перезапуску і автоматично підставляє в маніфест нові, актуальні значення ресурсів.

Режими роботи VPA (updateMode)

Рівень автономності інструменту можна гнучко налаштувати через поле updateMode:

Розбір YAML-маніфесту для VPA

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: database-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: postgres-db
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: postgres
      minAllowed:
        cpu: 200m
        memory: 250Mi
      maxAllowed:
        cpu: 2
        memory: 4Gi

Чому HPA та VPA не сумісні?

Маючи перед очима принципи роботи обох рівнів, легко зрозуміти головну помилку новачків — увімкнути HPA та VPA одночасно для одного й того самого застосунку за однією метрикою (наприклад, за CPU).

Це гарантовано призведе до інфраструктурного колапсу.

  1. Навантаження на под росте $\rightarrow$ CPU нагрівається.
  2. HPA бачить це і починає плодити нові поди.
  3. Водночас VPA теж це помічає і вирішує, що под треба збільшити. Для цього він вбиває под, щоб той перестворився з більшими ресурсами.
  4. Через зникнення пода навантаження на репліки, що залишилися, стає ще вищим. HPA панікує і створює ще більше подів, а VPA продовжує їх вбивати для апгрейду. Кластер починає неконтрольовано штормити, а сервіс лягає.

Запам’ятайте: використовувати HPA та VPA разом для одного Deployment можна лише тоді, коли вони налаштовані на різні метрики. Наприклад, HPA масштабує кількість подів на основі кількості HTTP-запитів (через KEDA), а VPA коригує пам’ять (RAM) на основі реального споживання контейнера.

Рівень інфраструктури 

Досі ми розглядали масштабування на рівні застосунків, коли Kubernetes оперував лише подами. Проте що відбувається, коли HPA або KEDA створюють нові поди, а на наявних нодах для них більше немає вільного місця?

У цей момент нові поди переходять у статус Pending (очікування), оскільки планувальник kube-scheduler просто не може знайти для них підхожий вузол. Щоб вирішити цю проблему, потрібне масштабування самого «заліза». В індустрії для цього використовуються два основні інструменти.

Cluster Autoscaler (CA)

Це традиційний компонент, який тісно інтегрується з API хмарних провайдерів (наприклад, AWS Auto Scaling Groups, Google Cloud Managed Instance Groups або Azure Scale Sets).

Він працює за реактивною логікою, орієнтуючись виключно на потреби планувальника:

  1. Він безперервно моніторить кластер на наявність подів у статусі Pending.
  2. Щойно такі поди з’являються, CA аналізує їхні параметри requests (запити ресурсів) та правила розміщення (affinity/tolerations).
  3. Після цього він надсилає запит до хмарного провайдера з вимогою збільшити кількість машин у відповідній групі вузлів (Node Group).
  4. Коли навантаження падає, CA шукає недовантажені ноди, плавно переносить з них поди на інші сервери, а порожні вузли видаляє, щоб оптимізувати витрати.

Розбір базового YAML-маніфесту для Cluster Autoscale

apiVersion: autoscaling/v2
kind: ClusterAutoscaler
metadata:
  name: cluster-autoscaler-config
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cluster-autoscaler
  minReplicas: 1
  maxReplicas: 8
  autoDiscovery:
    clusterName: production-kubernetes-cluster
    tags:
      k8s.io/cluster_autoscaler/enabled: "true"
  balanceSimilarNodeGroups: true

Важливий нюанс: Cluster Autoscaler не аналізує реальне завантаження процесора чи пам’яті на серверах. Якщо ваші ноди завантажені реальними процесами лише на 5%, але сума параметрів requests усіх подів на них досягла 100%, для Kubernetes цей сервер вважається повністю заповненим. CA почне замовляти нові машини, навіть якщо старі фактично проїдають бюджет.

Сучасна альтернатива: Karpenter

Останніми роками дедалі більше команд переходять від класичного CA до Karpenter — сучасного опенсорсного інструменту для масштабування інфраструктури, розробленого AWS, який зараз активно адаптується іншими хмарами.

Чому всі переходять на Karpenter?

Головний недолік Cluster Autoscaler полягає у прив’язці до жорстких хмарних Node Groups. Якщо поду потрібна специфічна нода (наприклад, з великою кількістю RAM або з GPU), а у вашій групі вузлів прописані лише стандартні машини, CA не зможе допомогти.

Karpenter працює інакше — за принципом Group-less Node Provisioning:

Завдяки відсутності проміжних шарів у вигляді хмарних груп автоскалювання, Karpenter здатний додати новий сервер до кластера за лічені секунди, тоді як класичному Cluster Autoscaler на це часто потрібно кілька хвилин.

Чек-лист для перевірки свого кластера 

Перед тим як повністю довірити інфраструктуру автоматиці, пройдіться цим коротким технічним списком, щоб переконатися, що кластер готовий до динамічних змін:

  1. [ ] Чи розгорнуто Metrics Server?
    Без нього стандартні HPA та VPA не зможуть отримувати дані про споживання CPU та пам’яті.
  2. [ ] Чи скрізь прописані requests?
    Якщо хоча б у кількох великих подів не вказано гарантований мінімум ресурсів, планувальник працюватиме некоректно, а Cluster Autoscaler може не запустити нові ноди вчасно.
  3. [ ] Чи немає конфлікту між HPA та VPA?
    Перевірте, щоб горизонтальне та вертикальне масштабування не були нацьковані на одну й ту саму метрику для одного Deployment.
  4. [ ] Чи захищені критичні застосунки за допомогою PDB?
    Переконайтеся, що для важливих сервісів налаштовані PodDisruptionBudgets, які захистять їх від випадкового повного видалення під час масштабування інфраструктури.
  5. [ ] Чи налаштовані обмеження minReplicas та maxReplicas?
    Перевірте запобіжники в HPA та VPA, щоб уникнути ситуації, коли збій або атака на сервіс змусить автоматику безконтрольно роздути кластер і спалити весь бюджет.

Корисні посилання

Exit mobile version