Оптимізація ресурсів у K8s: повний посібник з Autoscaling
Автомасштабування в Kubernetes — це динамічний процес автоматичного коригування обчислювальних ресурсів у кластері залежно від поточного навантаження. Його головна мета полягає у тому, щоб забезпечити безперебійну роботу застосунків під час напливу користувачів і водночас звільнити зайві потужності, коли потреба в них зникає.
Попри те, що близько 96% компаній уже перейшли на Kubernetes, середня утилізація процесора (CPU) у кластерах становить лише близько 13%. Тобто колосальний обсяг куплених потужностей просто проїдає бюджет.
Головна причина — так званий оверпровіженінг (over-provisioning), або штучне завищення лімітів:
- Перестрахування інженерів: завищення параметрів
requestsіз запасом, щоб уникнути дроселювання (CPU throttling) та аварійних зупинок (OOM-kills). - Статичні ліміти: ручне фіксування ресурсів у маніфестах, через що кластер продовжує утримувати й оплачувати сервери під час нічного зниження трафіку.
- Фрагментація нод: неоптимальне розкидання подів планувальником (kube-scheduler), коли на серверах залишаються дрібні шматки ресурсів, які не може зайняти жоден новий под.
Саме для розв’язання цих проблем і потрібна гнучка система автоматичного масштабування.
Архітектура Kubernetes Autoscaling
У Kubernetes не існує одного універсального інструменту для масштабування, оскільки архітектура всієї платформи розділена на рівні. Повноцінна автоматизація ресурсів складається з трьох взаємопов’язаних компонентів, кожен з яких виконує своє чітке завдання.
Горизонтальне масштабування подів
Horizontal Pod Autoscaling (HPA) — це масштабування в ширину.
Коли навантаження зростає, Kubernetes створює нові копії (репліки) подів, щоб розподілити між ними трафік. При спаді активності юзерів — зайві копії видаляються. Це базовий вибір для вебзастосунків та мікросервісів.
Вертикальне масштабування подів
Vertical Pod Autoscaler (VPA) — це, як ви вже догадались, масштабування вгору.
Замість створення нових подів, система змінює розмір уже наявних — автоматично додає або зменшує їм CPU та оперативну пам’ять. Підхід незамінний для баз даних або фонових завдань, які складно розпаралелити на багато копій.
Масштабування інфраструктури
Коли попередні інструменти намагаються запустити нові поди, а на серверах (нодах) немає вільного місця, поди зависають у статусі Pending. Інфраструктурний скейлер помічає це, автоматично додає у хмарі нові віртуальні машини, а при спаді навантаження — виводить порожні ноди з експлуатації.
Важливе правило архітектури: Масштабування навантажень (HPA/VPA) та масштабування інфраструктури повинні працювати в синергії. Автоматика на рівні застосунку створює попит на ресурси, а автоматика на рівні інфраструктури цей попит задовольняє.
Рівень робочих навантажень
Як ми вже з’ясували, рівень робочих навантажень відповідає за адаптацію самих застосунків під поточний потік запитів. Оскільки програми бувають різними — архітектурно та за типом споживання ресурсів — Kubernetes використовує два різні підходи, які ви вже знаєте: горизонтальний (HPA) та вертикальний (VPA).
Тепер зазирнемо під капот кожного з них.
HPA та скейлінг на основі подій
Процес керування є безперервним циклом зворотного зв’язку (feedback loop):
- Збір метрик
У кластері працює Metrics Server, який безперервно збирає дані про те, скільки ресурсів споживає кожен под. - Опитування контролером
HPA-контролер із фіксованим інтервалом (за замовчуванням — кожні 15 секунд) звертається до Metrics Server API. - Обчислення та реакція
Контролер порівнює поточні значення з цільовими (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
scaleTargetRef— вказує на конкретний застосунок (web-app), яким керує автоматика.minReplicas: 2таmaxReplicas: 10— жорсткі межі, які захищають кластер від неконтрольованого розростання або повного зникнення програми.averageUtilization: 50— якщо середнє споживання CPU серед усіх подів перевищить 50 %, HPA почне створювати нові репліки, щоб розвантажити систему.
Обмеження стандартного HPA
Попри просту логіку, класичний HPA має два суттєві недоліки:
- Запізнення: HPA реагує на події постфактум. Поки Metrics Server збере дані, а HPA вирахує нову кількість подів, застосунок під час раптового шквального трафіку може встигнути лягти.
- Сліпота до бізнес-метрик: стандартний HPA знає лише про CPU та RAM. Проте навантаження на сервіс може подвоїтися через чергу завдань, а процесор залишатиметься холодним.
Щоб обійти ці ліміти, в індустрії використовують KEDA (Kubernetes Event-driven Autoscaling) — зовнішню надбудову для K8s. KEDA діє проактивно і скейлить поди на основі зовнішніх подій. Наприклад, він може підключитися до черги повідомлений (RabbitMQ чи Apache Kafka) і миттєво додати поди, якщо бачить, що в черзі накопичилося понад 100 необроблених тасок.
Крім того, KEDA вміє масштабувати робочі навантаження до нуля. Якщо черга порожня, він повністю гасить поди застосунку, економлячи бюджет, а при появі нової задачі — миттєво піднімає їх назад.
VPA та конфлікти ресурсів
Якщо HPA плодив копії, то VPA діє вглиб — він не чіпає кількість подів, а автоматично змінює розмір (requests та limits CPU/RAM) всередині вже наявних контейнерів. Це рятує, коли застосунок архітектурно є монолітом або базою даних, яку не можна просто розмножити «в ширину».
Анатомія VPA
Для керування цим процесом архітектура VPA використовує три окремі службові компоненти:
- VPA Recommender: аналізує поточне споживання ресурсів та історію поведінки контейнера, розраховуючи для нього оптимальні значення CPU та RAM.
- VPA Updater: стежить за рекомендаціями. Якщо реальні потреби подів сильно відрізняються від того, що пропонує Recommender, він дає команду на видалення пода, щоб той перезапустився з новими параметрами.
- VPA Admission Controller: спеціальний вебхук, який перехоплює под у момент його перезапуску і автоматично підставляє в маніфест нові, актуальні значення ресурсів.
Режими роботи VPA (updateMode)
Рівень автономності інструменту можна гнучко налаштувати через поле updateMode:
Auto(типовий): VPA повністю керує процесом — сам вираховує, сам вбиває поди для оновлення і сам підставляє нові ресурси.Initial: VPA підставляє рекомендовані ресурси тільки в момент створення пода. Якщо под уже працює, VPA не буде його чіпати чи перезапускати.Off(режим рекомендацій): найбезпечніший варіант. VPA просто збирає статистику та пише свої поради в статус об’єкта, а інженери вносять зміни вручну.
Розбір 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
updateMode: "Auto"— дозволяє VPA самостійно перестворювати поди.minAllowedтаmaxAllowed— «запобіжники», які обмежують апетити VPA, щоб він випадково не зменшив ресурси до критичного мінімуму або не замовив занадто дорогі ліміти.
Чому HPA та VPA не сумісні?
Маючи перед очима принципи роботи обох рівнів, легко зрозуміти головну помилку новачків — увімкнути HPA та VPA одночасно для одного й того самого застосунку за однією метрикою (наприклад, за CPU).
Це гарантовано призведе до інфраструктурного колапсу.
- Навантаження на под росте $\rightarrow$ CPU нагрівається.
- HPA бачить це і починає плодити нові поди.
- Водночас VPA теж це помічає і вирішує, що под треба збільшити. Для цього він вбиває под, щоб той перестворився з більшими ресурсами.
- Через зникнення пода навантаження на репліки, що залишилися, стає ще вищим. 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).
Він працює за реактивною логікою, орієнтуючись виключно на потреби планувальника:
- Він безперервно моніторить кластер на наявність подів у статусі
Pending. - Щойно такі поди з’являються, CA аналізує їхні параметри
requests(запити ресурсів) та правила розміщення (affinity/tolerations). - Після цього він надсилає запит до хмарного провайдера з вимогою збільшити кількість машин у відповідній групі вузлів (Node Group).
- Коли навантаження падає, 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
autoDiscovery— дозволяє автоматично знаходити групи нод у хмарі за тегом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:
- Він повністю ігнорує концепцію Node Groups і спілкується з EC2/хмарним API напряму.
- Коли з’являється под у статусі
Pending, Karpenter миттєво оцінює його точні вимоги та самостійно конструює ідеальну ноду під цей конкретний под. - Він може замовити одну велику машину замість трьох маленьких, або навпаки — вибрати дешевшу Spot-інстанс (Preemptible VM), якщо под є некритичним і допускає переривання роботи.
Завдяки відсутності проміжних шарів у вигляді хмарних груп автоскалювання, Karpenter здатний додати новий сервер до кластера за лічені секунди, тоді як класичному Cluster Autoscaler на це часто потрібно кілька хвилин.
Чек-лист для перевірки свого кластера
Перед тим як повністю довірити інфраструктуру автоматиці, пройдіться цим коротким технічним списком, щоб переконатися, що кластер готовий до динамічних змін:
- [ ] Чи розгорнуто Metrics Server?
Без нього стандартні HPA та VPA не зможуть отримувати дані про споживання CPU та пам’яті. - [ ] Чи скрізь прописані
requests?
Якщо хоча б у кількох великих подів не вказано гарантований мінімум ресурсів, планувальник працюватиме некоректно, а Cluster Autoscaler може не запустити нові ноди вчасно. - [ ] Чи немає конфлікту між HPA та VPA?
Перевірте, щоб горизонтальне та вертикальне масштабування не були нацьковані на одну й ту саму метрику для одного Deployment. - [ ] Чи захищені критичні застосунки за допомогою PDB?
Переконайтеся, що для важливих сервісів налаштованіPodDisruptionBudgets, які захистять їх від випадкового повного видалення під час масштабування інфраструктури. - [ ] Чи налаштовані обмеження
minReplicasтаmaxReplicas?
Перевірте запобіжники в HPA та VPA, щоб уникнути ситуації, коли збій або атака на сервіс змусить автоматику безконтрольно роздути кластер і спалити весь бюджет.