Як зменшити витрати Kubernetes на 40-70%: VPA, Karpenter, OpenCost у 2026

Покроковий посібник зі зменшення витрат на Kubernetes у 2026 році — від 40% до 70% економії. VPA та Goldilocks для right-sizing, Karpenter зі Spot-інстансами, OpenCost для моніторингу. Робочі YAML-приклади для copy-paste.

Чому оптимізація витрат Kubernetes — це критично у 2026 році

Ось чесна правда: понад 68% організацій у 2026 році перевитрачають на Kubernetes від 20% до 40% свого бюджету. І причина банально проста — розробники налаштовують ресурси «про запас», тестові середовища працюють 24/7, а аудит реального споживання ніхто не проводить. У результаті 80-90% pod-ів у типовому кластері мають завищені requests для CPU та пам'яті.

Це як платити за п'ятикімнатну квартиру, коли вам вистачило б двокімнатної.

Якщо ваша організація витрачає $10 000 на місяць на Kubernetes, цілком реально знизити цю суму до $4 000-6 000 — і без жодної втрати продуктивності. У цьому посібнику ми пройдемося по конкретних інструментах та YAML-конфігураціях: Vertical Pod Autoscaler (VPA) для right-sizing, Goldilocks для візуалізації рекомендацій, Karpenter для розумного автомасштабування вузлів та OpenCost для моніторингу витрат. Все з прикладами, які можна копіювати й одразу використовувати.

Крок 1: Розуміння requests і limits — фундамент усього

Перш ніж щось оптимізувати, варто розібратися, як Kubernetes взагалі розподіляє ресурси. Кожен контейнер у pod має два ключові параметри:

  • Requests (запити) — мінімальний обсяг CPU та пам'яті, який планувальник резервує для контейнера. Саме на основі requests Kubernetes вирішує, на який вузол поставити pod.
  • Limits (обмеження) — максимум ресурсів, який контейнер може використати. Перевищення ліміту CPU призведе до throttling, а перевищення ліміту пам'яті — до OOMKill (і це завжди неприємний сюрприз).

А ось типовий приклад завищених ресурсів, який я постійно зустрічаю в продакшн-кластерах:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: api
        image: myapp:latest
        resources:
          requests:
            cpu: "2000m"      # Запит: 2 повних ядра
            memory: "4Gi"     # Запит: 4 ГБ пам'яті
          limits:
            cpu: "4000m"
            memory: "8Gi"

Але коли дивишся на реальне споживання через Prometheus — pod використовує лише 200m CPU (10% від запиту) та 512Mi пам'яті (12.5%). Решта — чисте марнотратство, за яке ви справно платите кожного місяця.

Важливе правило: для CPU варто розглянути варіант без limits — це дозволить pod-ам використовувати вільні ресурси вузла без ризику throttling. А от для пам'яті limits ставте завжди, бо поведінка OOM без них непередбачувана і, чесно кажучи, зазвичай катастрофічна.

Крок 2: Right-sizing за допомогою VPA та Goldilocks

Встановлення Vertical Pod Autoscaler (VPA)

VPA аналізує реальне споживання ресурсів вашими pod-ами та генерує рекомендації щодо оптимальних значень requests і limits. Головне — почніть із режиму рекомендацій. Він не буде автоматично перезапускати pod-и, а просто покаже, які значення були б оптимальними.

# Встановлення metrics-server (якщо ще не встановлений)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Встановлення VPA
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh

# Перевірка встановлення
kubectl get pods -n kube-system | grep vpa

Тепер створіть VPA-об'єкт для вашого deployment-у в режимі Off (тільки рекомендації, без автоматичних змін):

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-server-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: "Off"   # Тільки рекомендації
  resourcePolicy:
    containerPolicies:
    - containerName: api
      minAllowed:
        cpu: "50m"
        memory: "128Mi"
      maxAllowed:
        cpu: "4000m"
        memory: "8Gi"

Дайте йому 24-48 годин на збір метрик, а потім перевірте рекомендації:

kubectl get vpa api-server-vpa -n production -o yaml

VPA покаже три рівні рекомендацій для кожного контейнера:

  • lowerBound — мінімум, нижче якого pod може зазнавати throttling
  • target — рекомендоване значення для requests (та сама «золота середина»)
  • upperBound — максимум, вище якого pod навряд чи знадобляться додаткові ресурси

Goldilocks: візуальний дашборд для right-sizing

Якщо створювати VPA-об'єкти вручну для кожного deployment-у здається нудним — Goldilocks від Fairwinds зробить це за вас. Просто позначте namespace, і він автоматично створить VPA для всіх deployment-ів та покаже рекомендації у зручному веб-інтерфейсі.

# Встановлення Goldilocks через Helm
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm repo update
helm install goldilocks fairwinds-stable/goldilocks \
  --namespace goldilocks \
  --create-namespace \
  --set dashboard.enabled=true

# Перевірка pod-ів
kubectl get pods -n goldilocks

Увімкніть моніторинг для потрібного namespace:

# Позначте namespace для аналізу
kubectl label namespace production goldilocks.fairwinds.com/enabled=true

# Відкрийте дашборд
kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80
# Перейдіть на http://localhost:8080

Дашборд покаже для кожного контейнера поточні значення requests/limits поруч із рекомендаціями VPA. Дуже зручно — одразу видно, де найбільше перевитрат. Він також пропонує два варіанти QoS-класів:

  • Guaranteed — requests дорівнюють limits (вищий пріоритет, але менша гнучкість)
  • Burstable — requests нижчі за limits (pod може «вибухнути» і використати більше ресурсів за потреби)

Порада з досвіду: не поспішайте застосовувати рекомендації одразу. Зберіть дані мінімум за 2 тижні, а ще краще — за повний місяць, щоб врахувати всі паттерни навантаження, включаючи піки та batch-завдання. Я бачив випадки, коли рекомендації на основі тижневих даних не враховували місячні піки — і це закінчувалося аварійними OOM-подіями.

Крок 3: Розумне автомасштабування вузлів із Karpenter

Karpenter — це, по суті, наступне покоління автомасштабування вузлів для Kubernetes на AWS. На відміну від Cluster Autoscaler, який просто збільшує заздалегідь визначені NodeGroups, Karpenter динамічно підбирає оптимальний тип інстансу для кожного pod-у. Він враховує вартість, доступність і вимоги — і часто знаходить варіанти, про які ви навіть не думали.

Компанії, що мігрували з Cluster Autoscaler на Karpenter, повідомляють про скорочення витрат на обчислення приблизно на 30%. Непогано, правда?

Базова конфігурація NodePool

NodePool — це основний CRD Karpenter, що визначає правила створення вузлів. Ось конфігурація для production-кластера з підтримкою Spot-інстансів:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general-workloads
spec:
  template:
    spec:
      requirements:
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
        - key: kubernetes.io/os
          operator: In
          values: ["linux"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["2"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      expireAfter: 720h  # 30 днів
  limits:
    cpu: 1000
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  role: "KarpenterNodeRole-my-cluster"
  amiSelectorTerms:
    - alias: "al2023@latest"
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: "my-cluster"
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: "my-cluster"

Що тут важливо розуміти:

  • capacity-type: ["spot", "on-demand"] — Karpenter спершу спробує Spot-інстанси (знижка до 90%!), а якщо Spot недоступний — візьме On-Demand
  • instance-category: ["c", "m", "r"] — дозволяє обирати з обчислювальних (c), загального призначення (m) та пам'яті-оптимізованих (r) інстансів
  • consolidationPolicy: WhenEmptyOrUnderutilized — Karpenter сам замінить недовантажені вузли компактнішими. Це як автоматичний «прибиральник» для вашого кластера

NodePool для Dev/Staging — максимальна економія

Для непродакшн середовищ можна і потрібно бути агресивнішими:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: dev-pool
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"]  # Тільки Spot для dev
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r", "t"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["2"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      expireAfter: 168h  # 7 днів
  limits:
    cpu: 200
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 10s  # Агресивна консолідація
    budgets:
      - nodes: "30%"

Окремий NodePool для критичних сервісів

Для баз даних, черг та інших stateful-сервісів потрібен окремий NodePool із політикою WhenEmpty — тут стабільність важливіша за економію:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: stable-pool
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]  # Тільки On-Demand
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m", "r"]
      taints:
        - key: stable
          value: "true"
          effect: NoSchedule
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
  disruption:
    consolidationPolicy: WhenEmpty  # Видаляти тільки порожні вузли
    consolidateAfter: 5m

Щоб pod потрапив на стабільний вузол, додайте відповідний toleration:

tolerations:
  - key: stable
    operator: Equal
    value: "true"
    effect: NoSchedule

Крок 4: Моніторинг витрат із OpenCost

OpenCost — безкоштовний open-source проєкт CNCF для моніторингу витрат Kubernetes у реальному часі. Він покаже вартість кожного namespace, deployment, pod та навіть окремого контейнера. Без нього ви, по суті, оптимізуєте наосліп.

Встановлення OpenCost

# Встановлення через Helm
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update
helm install opencost opencost/opencost \
  --namespace opencost \
  --create-namespace \
  --set opencost.ui.enabled=true \
  --set opencost.prometheus.internal.enabled=true

# Перевірка
kubectl get pods -n opencost

# Відкрити UI
kubectl -n opencost port-forward svc/opencost 9090:9090
# Перейдіть на http://localhost:9090

API-запити для автоматизації

OpenCost має REST API, який можна інтегрувати з вашими процесами. Ось приклад отримання витрат за namespace за останні 48 годин:

# Витрати за namespace
curl -s "http://localhost:9090/allocation/compute?window=48h&aggregate=namespace" \
  | jq '.data[] | to_entries[] | {namespace: .key, totalCost: .value.totalCost}'

# Витрати за deployment у конкретному namespace
curl -s "http://localhost:9090/allocation/compute?window=7d&aggregate=deployment&filterNamespaces=production" \
  | jq '.data[]'

Цікава новинка 2026 року: OpenCost тепер підтримує MCP-сервер (Model Context Protocol), що дозволяє AI-агентам напряму запитувати дані про витрати. Уявіть: ваш AI-асистент сам аналізує витрати і пропонує оптимізації. Ми живемо в цікавий час.

OpenCost vs Kubecost: що обрати

OpenCost — це ядро, на якому побудований Kubecost. Для більшості команд OpenCost цілком достатньо. Обирайте Kubecost Enterprise тільки якщо вам дійсно потрібні:

  • Уніфіковані дашборди для кількох кластерів
  • Врахування знижок (Reserved Instances, Spot, кредити)
  • Прогнозування витрат та виявлення аномалій
  • Інтеграція зі Slack, PagerDuty, Jira

Крок 5: Governance — запобігання марнотратству на рівні політик

Інструменти — це чудово, але без організаційних політик витрати неминуче повернуться до попередніх рівнів. Повірте, я це бачив не раз. Використовуйте Kyverno або OPA Gatekeeper для автоматичного дотримання правил.

Приклад: обов'язкові resource requests через Kyverno

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-requests
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-resource-requests
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "CPU та memory requests обов'язкові для всіх контейнерів"
      pattern:
        spec:
          containers:
          - resources:
              requests:
                memory: "?*"
                cpu: "?*"

Приклад: обмеження максимальних requests

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: limit-resource-requests
spec:
  validationFailureAction: Enforce
  rules:
  - name: limit-cpu-request
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "CPU request не може перевищувати 4 ядра без погодження з Platform-командою"
      deny:
        conditions:
          any:
          - key: "{{ request.object.spec.containers[].resources.requests.cpu }}"
            operator: GreaterThan
            value: "4000m"

Також не забудьте про ResourceQuotas на рівні namespace — це простий, але ефективний спосіб обмежити загальне споживання кожною командою:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "20"
    requests.memory: "40Gi"
    limits.cpu: "40"
    limits.memory: "80Gi"
    pods: "100"

Покроковий план впровадження

Не намагайтеся впровадити все одразу — це вірний шлях до хаосу. Ось порядок, який працює на практиці:

  1. Тиждень 1-2: Встановіть OpenCost і зберіть базовий рівень витрат. Визначте, скільки ви витрачаєте зараз та які namespace найдорожчі. Без цієї базової лінії ви не зможете виміряти прогрес.
  2. Тиждень 3-4: Встановіть Goldilocks та VPA в режимі рекомендацій. Позначте всі production namespace для аналізу. Нехай збирають дані — не поспішайте.
  3. Тиждень 5-6: Застосуйте рекомендації right-sizing для найбільш перевитрачених deployment-ів. Починайте з dev/staging, а потім обережно переходьте до production.
  4. Тиждень 7-8: Впровадьте Karpenter замість Cluster Autoscaler. Знову ж таки — спочатку dev-кластер, налаштуйте Spot-інстанси та консолідацію, переконайтеся що все працює стабільно.
  5. Тиждень 9-10: Додайте Kyverno-політики для запобігання майбутньому перевитрачанню. Налаштуйте ResourceQuotas для кожної команди.
  6. Постійно: Щомісяця переглядайте дашборд OpenCost та рекомендації Goldilocks. Оптимізація витрат — це не проєкт із кінцевою датою, а безперервний процес.

FAQ — найпоширеніші запитання

Чи безпечно використовувати Spot-інстанси у production?

Так, але з правильним підходом. Використовуйте Spot для stateless-сервісів із кількома репліками, налаштуйте PodDisruptionBudgets та розподіліть pod-и по кількох Availability Zones. Karpenter автоматично обирає Spot-інстанси з найменшою ймовірністю переривання. А от для баз даних та інших критичних stateful-сервісів — тільки On-Demand через окремий NodePool. Тут краще не ризикувати.

Чи може VPA конфліктувати з HPA?

Може, і це поширена пастка. Якщо обидва налаштовані на однакові метрики (наприклад, CPU), VPA збільшує requests → відсоток утилізації падає → HPA масштабує вниз. Замкнене коло. Рішення: використовуйте VPA для пам'яті, а HPA — для CPU, або (ще краще) налаштуйте HPA на кастомні метрики — кількість запитів, довжину черги тощо.

Скільки часу потрібно для збору достатніх даних VPA?

Мінімум 2 тижні, а краще — повний місяць. Це дозволяє VPA врахувати робочі та вихідні дні, піки навантаження та batch-завдання. Для короткоживучих pod-ів (CI-ранери, batch-job-и) VPA, чесно кажучи, не дуже підходить — вони не генерують достатньо історії для якісних рекомендацій.

Яку реальну економію можна очікувати?

За даними 2026 року: right-sizing з VPA дає 30-50% скорочення витрат на перевитрачені ресурси. Karpenter із Spot-інстансами — ще 20-30% зверху. Очищення зомбі-ресурсів додасть 10-20%. Загалом організації досягають скорочення витрат на Kubernetes на 40-70%. Звучить неймовірно, але це реальні цифри — просто більшість кластерів настільки неоптимізовані, що навіть базові кроки дають величезний ефект.

Чи працює Karpenter тільки з AWS?

Станом на 2026 рік Karpenter є офіційним проєктом Kubernetes SIG Autoscaling, але production-ready реалізація є тільки для AWS (EKS). Якщо ви на Azure AKS чи GCP GKE — використовуйте вбудований Node Auto-provisioner або Cluster Autoscaler у поєднанні з VPA та Goldilocks для right-sizing. Результат буде не таким вражаючим, але все одно відчутним.

Про Автора Editorial Team

Our team of expert writers and editors.