Kubernetes у продакшені: probes, requests/limits і автоскейлінг
Три налаштування, без яких Deployment не готовий до продакшену: перевірки здоров'я, ресурси контейнерів і HPA. Що ставити, які значення і як не вбити сервіс власними руками.
Deployment з попередньої статті запуститься, але в продакшені швидко з'являться питання: чому трафік іде на под, що ще не прогрівся? чому сусідній сервіс з'їв усю пам'ять вузла? чому в пікові години все гальмує? Відповіді — у трьох налаштуваннях.
Probes: як Kubernetes дізнається, що под здоровий
| Probe | Питання | Якщо не проходить |
|---|---|---|
startupProbe |
Застосунок уже запустився? | Інші проби не запускаються; після ліміту — рестарт |
readinessProbe |
Готовий приймати трафік? | Под прибирається з балансування (без рестарту) |
livenessProbe |
Живий чи завис? | Контейнер перезапускається |
containers:
- name: api
image: ghcr.io/acme/api:1.4.2
startupProbe:
httpGet: { path: /healthz, port: 8000 }
periodSeconds: 5
failureThreshold: 24 # до 2 хвилин на старт
readinessProbe:
httpGet: { path: /ready, port: 8000 }
periodSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet: { path: /healthz, port: 8000 }
periodSeconds: 10
failureThreshold: 3ОбережноНе перевіряйте в liveness зовнішні залежності (базу, Redis, інші сервіси). Якщо база ляже на хвилину, liveness почне перезапускати всі поди одночасно — і ви отримаєте каскадну аварію замість короткої деградації. Залежності — лише в readiness, а liveness має відповідати на питання «чи не завис сам процес».
Типовий розподіл:
/healthz— процес відповідає (без звернень до залежностей);/ready— прогрів завершено, пул з'єднань з БД є, міграції пройшли.
Requests і limits
resources:
requests:
cpu: 250m # 0.25 ядра — гарантовано, за цим планувальник вибирає вузол
memory: 384Mi
limits:
memory: 512Mi # більше — OOMKilled- requests — скільки ресурсу резервується. Планувальник ставить под лише на вузол, де є стільки вільного.
- limits — стеля. Перевищення пам'яті → контейнер вбиває OOM killer (
OOMKilled). Перевищення CPU → троттлінг (процес сповільнюється, але не вмирає).
ПорадаПоширена практика — ставити limit на пам'ять (≈ requests + запас) і не ставити limit на CPU. CPU-ліміт часто спричиняє троттлінг навіть тоді, коли на вузлі є вільні ядра, і це виглядає як «незрозумілі» стрибки латентності.
Як підібрати значення: запустіть сервіс під реальним навантаженням, подивіться споживання (kubectl top pods, Prometheus) і поставте requests трохи вище типового, а memory limit — вище піку.
Класи QoS
| Клас | Умова | Кого виселяють першим |
|---|---|---|
| Guaranteed | requests = limits для CPU і пам'яті | Останніми |
| Burstable | Є requests, але не дорівнюють limits | Посередині |
| BestEffort | Немає ні requests, ні limits | Першими |
Под без requests — BestEffort: його виселять першим при нестачі пам'яті на вузлі.
HPA: горизонтальний автоскейлінг
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 65 }
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # не скидати поди при кожному короткому спадіHPA рахує утилізацію відносно requests. Без requests.cpu він не працюватиме — це найчастіша причина «HPA показує <unknown>».
Для черг і подій масштабування за CPU погано підходить — краще за довжиною черги чи кількістю запитів. Для цього використовують зовнішні метрики або KEDA.
PodDisruptionBudget
Оновлення вузлів, дренаж, автоскейлер кластера — усе це «добровільні» вимкнення подів. PDB не дає вимкнути забагато одночасно:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api
spec:
minAvailable: 2
selector:
matchLabels: { app: api }Коректне завершення
При видаленні пода Kubernetes надсилає SIGTERM і чекає terminationGracePeriodSeconds (30 с за замовчуванням). Застосунок має перестати приймати нові запити, дообробити поточні й закритися. Короткий preStop зі sleep 5 дає балансувальникам час прибрати под з ротації до того, як він перестане відповідати.
Под постійно перезапускається зі статусом OOMKilled. Що перевірити?
Memory limit замалий для реального споживання або в застосунку витік пам'яті. Подивіться графік пам'яті до моменту вбивства: якщо вона росте до ліміту поступово годинами — схоже на витік; якщо одразу після старту чи під навантаженням — збільште limit і requests. Для JVM, Node.js і Python перевірте, що розмір heap налаштовано з урахуванням ліміту контейнера.
Збережіть статтю собі
Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.
Увійти через Google Інші способи входу