Дуже правильне діло – моніторити, наскільки ефективно використовується кластер, особливо, якщо ресурси деплояться розробниками, які не сильно вникають у requests, і встановлюють завищені значення “про запас”. Запас, звичайно, потрібен, але й просто так реквестити ресурси ідеї погана.
Наприклад, у вас є WorkerNode з 4 vCPU (4000 milicpu) та 16 ГБ оперативної пам’яті, і ви створюєте Kubernetes Deployment, у якому для подів задаєте CPU requests 2500m і 4 Гб пам’яті. Після запуску одного пода – він зареквестить більше половини доступного процесорного часу, і під час запуску другого поду Kubernetes повідомить про нестачу ресурсів на доступних нодах, що призведе до запуску ще одного WorkerNode, який, зрозуміло, відразиться на загальній вартості кластера.
Щоб уникнути цього, є кілька утиліт, таких як Kubernetes Resource Report та Kubecost.
Зміст
Kube Resource Report
Kubernetes Resource Report – найпростіший у запуску та можливостях: просто виводить ресурси групуючи їх за типом, і відображає статистику – скільки CPU/MEM requested і скільки реально використовується.
Мені вона подобається саме простотою – просто запускаємо, раз в пару тижнів дивимося що відбувається в кластері, і за необхідності пінгуємо розробників із питанням “А вам насправді потрібно 100500 гіг пам’яті для цієї апки? »
Є Helm-чарт, але він оновлюється рідко, тому простіше встановити з маніфестів.
Створюємо Namespace:
[simterm]
$ kk create ns kube-resource-report namespace/kube-resource-report created
[/simterm]
Завантажуємо репозиторій з kube-resource-report
:
[simterm]
$ git clone https://codeberg.org/hjacobs/kube-resource-report $ cd kube-resource-report/
[/simterm]
У каталозі deploy
вже є файл Kustomize – задамо в ньому деплой в наш неймспейс:
[simterm]
$ echo "namespace: kube-resource-report" >> deploy/kustomization.yaml
[/simterm]
Перевіряємо:
[simterm]
$ cat deploy/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml - rbac.yaml - service.yaml - configmap.yaml namespace: kube-resource-report
[/simterm]
Встановлюємо:
[simterm]
$ kubectl apply -k deploy/ serviceaccount/kube-resource-report created clusterrole.rbac.authorization.k8s.io/kube-resource-report created clusterrolebinding.rbac.authorization.k8s.io/kube-resource-report created configmap/kube-resource-report created service/kube-resource-report created deployment.apps/kube-resource-report created
[/simterm]
Відкриваємо собі доступ до Service:
[simterm]
$ kubectl -n kube-resource-report port-forward svc/kube-resource-report 8080:80
[/simterm]
Відкриваємо репорт в браузері:
Далі переходимо, наприклад, до Namespaces, сортуємо колонки за CR (CPU Requested):
При наведенні курсора на повзунок Kube Resource Report підкаже оптимальне з його точки зору значення.
Далі думаємо самі – чи дійсно потрібно стільки requests, чи його можна зменшити.
У цьому випадку у нас Apache Druid з 16 подами, в кожній працює JVM, яка і процесор і пам’ять любить, і для Druid процесор бажано виділяти по одному ядру на кожен thread виконання Java, тому ОК – нехай буде 14,65 процесора.
Kubecost
Kubecost – це Kube Resource Report на стероїдах. Вміє рахувати трафік, відправляти алерти, генерує метрики для Prometheus, має свої дашборди Grafana, може підключатися до кількох кластерів Kubernetes та багато іншого.
Місцями не без багів, але в цілому штука приємна.
Правда, вартість бізнес-ліцензії в 499 доларів трохи завищена, як на мене. Втім для базових речей цілком доступна Free версія.
“Під капотом” використовує свій Prometheus для зберігання даних. Можна відключити і використовувати зовнішній, але не рекомендується .
Installation
Основні доступні параметри описані в документації на Github , також можна переглянути дефолтні values його Helm-чарту.
Потребує реєстрації для отримання ключа – заходимо на https://www.kubecost.com/install.html , вказуємо пошту – і відразу переадресує на інструкцію з вашим ключем:
Helm chart values
Поспішати з установкою не будемо – спочатку створимо свої values.
Якщо ви вже маєте Kube Prometheus Stack, є Grafana і NodeExporter – то в Kubecost їх має сенс відключити. Крім того, відключимо kube-state-metrics
, що б не дублювали дані в моніторингу.
Що б Prometheus із нашого власного стека почав збирати метрики Kubecost – налаштуємо створення ServiceMonitor і додамо йому labels
– тоді можна буде генерувати свої алерти та використовувати Grafana dashboard.
А ось якщо відключити запуск вбудованої Grafana – под с kubecost-cost-analyzer
не стартує. Не знаю – бага чи фіча. Але в ній є свої дашборды які можуть бути корисними, тож можна залишити.
Ще можна включити networkCosts
, але мені так і не вдалося побачити адекватних витрат на трафік – можливо, неправильно налаштував.
networkCosts
може бути достатньо прожорливим по ресурсам – треба моніторити використання ЦПУ.
Власне, сам values.yaml
:
kubecostToken: "c2V***f98" kubecostProductConfigs: clusterName: development-qa-data-services prometheus: kube-state-metrics: disabled: true nodeExporter: enabled: false serviceAccounts: nodeExporter: create: false serviceMonitor: enabled: true additionalLabels: release: prometheus networkCosts: enabled: true podMonitor: enabled: true config: services: amazon-web-services: true
Встановлюємо в Namespace kubecost
:
[simterm]
$ helm repo add kubecost https://kubecost.github.io/cost-analyzer/ $ helm upgrade --install -n kubecost --create-namespace -f values.yaml kubecost kubecost/cost-analyzer
[/simterm]
Відкриваємо порт:
[simterm]
$ kubectl -n kubecost port-forward svc/kubecost-cost-analyzer 9090:9090
[/simterm]
Перевіряємо поды – чи запустився kubecost-cost-analyzer
:
[simterm]
$ kubectl -n kubecost get pod NAME READY STATUS RESTARTS AGE kubecost-cost-analyzer-5f5b85bf59-f22ld 2/2 Running 0 59s kubecost-grafana-6bd995d6f9-kslh2 2/2 Running 0 63s kubecost-network-costs-22dps 1/1 Running 0 64s kubecost-network-costs-m7rf5 1/1 Running 0 64s kubecost-network-costs-tcdvn 1/1 Running 0 64s kubecost-network-costs-xzvsz 1/1 Running 0 64s kubecost-prometheus-server-ddb597d5c-dvrgc 2/2 Running 0 6m49s
[/simterm]
Відкриваємо доступ до kubecost-cost-analyzer
Service:
[simterm]
$ kubectl -n kubecost port-forward svc/kubecost-cost-analyzer 9090:9090
[/simterm]
І переходимо на http://localhost:9090.
Тут скрин з Kubecost, який вже майже тиждень запущено на одному з наших кластерів:
Коротко оглянемо основні пункти меню.
Assets
Для розуміння витрат краще почати з пункту Assets , де виводиться вартість “заліза”:
Бачимо, що в день наш кластер коштує 43 долари.
Можна “провалитися” глибше в деталі кластера, і побачити розбивку по ресурсам – WorkerNodes, лоад-балансерам, дискам та вартість самого AWS Elastic Kubernetes Service:
Переходимо ще далі, в Nodes:
І дивимось деталі вартості по конкретній ноді:
Перевіряємо:
0.167 за годину, як Kubecost і репортить в Hourly Rate.
Для налаштування витрат на AWS Spot Instances – див. Spot Instance data feed та AWS Spot Instances.
Cost Allocation
Відображає куди в самому Кубері витрачаються ресурси:
Kubecost враховує вартість CPU та RAM на WorkerNodes і, відповідно, виводить вартість кожного неймспейса залежно від його requests і usage.
Див. Pod resource efficiency.
Тут наш Apache Druid має реквестів CPU на цілих 48 долларів за тиждень або 4.08 в день.
Переходимо далі, і маємо картину по конкретним контролерам – StatefulSet, Deployment:
Колонки тут:
- CPU, RAM: вартість використовуваних ресурсів в залежності від вартості ресурсів WorkerNode
- PV: вартість PersistentVolume у вибраному контролері, тобто для StaefulSet MiddleManager маємо PV, котрий являє собою AWS EBS, за який ми платимо гроші
- Network: треба перевіряти, бо якось дивно рахує – дуже мало
- LB: LoadBalancers по вартості в AWS
- Shared: загальні ресурси, які не будут рахуватися окремо, наприклад неймспейс
kube-system
, налаштовується в http://localhost:9090/settings > Shared Cost - Efficiency: утилізація vs реквесты за формулою:
((CPU Usage / CPU Requested) * CPU Cost) + (RAM Usage / RAM Requested) * RAM Cost) / (RAM Cost + CPU Cost))
основний показник ефективності ресурсу, див. Efficiency and Idle
Якщо перейти ще глибше – буде посилання на Grafana, де можна переглянути використання ресурсів конкретним подом:
Правда, “з коробки” не відображаються метрики в RAM Requested.
Для перевірки метрик можна зайти на локальний Pometheus:
[simterm]
$ kubectl -n kubecost port-forward svc/kubecost-prometheus-server 9091:80
[/simterm]
І так – kube_pod_container_resource_requests_memory_bytes
пуста:
Тому що метрика теперь називаєтся kube_pod_container_resource_requests
з resource="memory"
, треба оновити запрос в цій Графані:
avg(kube_pod_container_resource_requests{namespace=~"$namespace", pod="$pod", container!="POD", resource="memory"}) by (container)
__idle__
Витрати __idle__
– різниця між вартістю ресурсів виділених під існуючі об’єкти (поди, деплойменти) – їх реквести і реальний usage, та “заліза, що простоює”, на якому вони працюють, тобто не зайняті ЦПУ/пам’ять, які можна використовувати під запуск нових ресурсів.
Savings
Тут зібрані поради щодо оптимізації витрат:
Наприклад, у “Right-size your container requests” зібрані рекомендації щодо налаштувань реквестів для ресурсів – аналог репортів у Kubernetes Resource Report:
Глянемо той же Apache Druid:
Тут явний овер-реквест по CPU, і Kubecost рекомендує зменшити ці реквести:
Але про Druid вже писалося вище – JVM, на кожен под MiddleManager ми запускаємо один Supervisor із двома Tasks, а під кожну Task бажано виділяти по повному ядру. Тож залишаємо, як є.
Корисна штука “Delete unassigned resources” – у нас, наприклад, знайшлася пачка EBS, що не використовуються:
Health
Теж корисна штука, що відображає основні проблеми із кластером:
kubecost-network-costs
активно використовує CPU, вище своїх реквестів, і Kubernetes його тротлить.
Alerts
Тут можемо налаштувати алерти, але мені вдалося налаштувати відправку тільки через Slack Webhook:
Документація – Alerts.
Prometehus Alertmanager можна налаштувати через values , але використовується свій локальний, який запускається разом з Prometheus, а як йому налаштувати роути – не знайшов.
Приклад алерту, який можна налаштувати в Kubecost:
global: notifications: alertConfigs: alerts: - type: budget threshold: 1 window: 1d aggregation: namespace filter: druid alertmanager: enabled: true fqdn: http://prometheus-kube-prometheus-alertmanager.monitoring.svc
Тут додаємо алерт з типом budget
, в якому перевіряємо вартість неймспейсу druid
за останній день, і алертимо, якщо він стає дорожчим за 1 долар.
Оновлюємо сетап:
[simterm]
$ helm upgrade --install -n kubecost -f values.yaml kubecost kubecost/cost-analyzer
[/simterm]
Алерт з’являється у списку:
Але на кнопку Test не реагує, і в локальному Alertmanager алерт не з’являється.
Slack webhook
Спробуємо через Slack webhook, документація тут>>>.
Створюємо Application:
Переходимо в Webhooks:
Активуємо та натискаємо Add New Webhook:
Вибираємо канал:
Додаємо URL у Kubecost, і тестуємо:
Final values.yaml
Зрештою для тесту зібрав такий values:
kubecostToken: "c2V***f98" kubecostProductConfigs: clusterName: development-qa-data-services global: notifications: alertConfigs: globalSlackWebhookUrl: https://hooks.slack.com/services/T03***c1f alerts: - type: assetBudget threshold: 30 window: 1d aggregation: type filter: 'Node' - type: assetBudget threshold: 4 window: 1d aggregation: type filter: 'LoadBalancer' - type: assetBudget threshold: 3 window: 1d aggregation: type filter: 'Disk' - type: assetBudget threshold: 40 window: 3d aggregation: cluster filter: 'development-qa-data-services' - type: spendChange relativeThreshold: 0.01 # change relative to baseline average cost. Must be greater than -1 (can be negative). window: 1d baselineWindow: 7d # previous window, offset by window aggregation: namespace filter: default, druid - type: spendChange relativeThreshold: 0.01 window: 1d baselineWindow: 7d aggregation: cluster filter: 'development-qa-data-services' - type: health # Alerts when health score changes by a threshold window: 10m threshold: 1 prometheus: kube-state-metrics: disabled: true nodeExporter: enabled: false serviceAccounts: nodeExporter: create: false #serviceMonitor: # enabled: true # additionalLabels: # release: prometheus networkCosts: enabled: true podMonitor: enabled: true config: destinations: direct-classification: - region: "us-west-2" zone: "us-west-2c" ips: - "10.0.64.0/19" - "10.0.160.0/20" - "10.0.208.0/21" - region: "us-west-2" zone: "us-west-2d" ips: - "10.0.216.0/21" - "10.0.96.0/19" - "10.0.176.0/20" services: amazon-web-services: true
Тут тестові алерти, які можна буде в принципі тягнути у продакшен.
ServiceMonitor для отримання метрик у зовнішньому Prometheus відключив, бо сенсу поки що не бачу – алертити буде через Slack Webhook своїми алертами, а дашборда для Grafana у вбудованій Графані краща, і їх там кілька.
Додав direct-classification
для networkCosts
– подивимося, можливо покаже більш правильні дані щодо трафіку.
#TODO
З чим поки що не вдалося розібратися:
- алерти через Alertmanager (можливо, має сенс таки спробувати відключити внутрішній Prometheus)
- Kubecost не бачить Node Exporter (перевіряти на сторінці http://localhost:9090/diagnostics ), але це наче ні на що не впливає – основні метрики отримує від cAdvisor
- витрати на нетворкінг занадто маленькі (але це не точно)
Не робив/не тестував:
- не налаштовував Cost Usage Reports для AWS , див. AWS Cloud Integration
- не налаштовував AWS Spot Instances прайсинг
- не додав Ingress, тому що у нас AWS ALB Controller, і треба робити авторизацію, а SAML в Kubecost доступний тільки в Premium
В цілому, на цьому все.
Система цікава та корисна, але є баги та складності, з якими треба розбиратися.