Как сократить затраты на кластеры Kubernetes? Обзор OpenCost
Рассказываем, как добавить щепотку FinOps в жизнь кластера и мониторить потребление ресурсов с помощью OpenCost.
Что такое FinOps и зачем он в Kubernetes
Вне зависимости от того, кто вы: небольшой стартап или развитая компания — задача управления затратами особенно важна. Модное понятие FinOps, оно же Financial Operations или Cloud Financial Operations, помогает организациям наиболее эффективно и экономически выгодно использовать облачные ресурсы. Другими словами — привязать вычислительные мощности к деньгам и учитывать стоимость IT-инфраструктуры в бюджете проекта.
Одна из наиболее популярных сред развертывания Kubernetes — облако. Например, у нас в Selectel есть сервис управления кластерами Managed Kubernetes. Клиенты могут использовать отказоустойчивые и автомасштабируемые кластеры в облачной платформе. При этом — создавать их в фиксированной или произвольной конфигурации с разными типами групп нод, платить только за услугу и используемые ресурсы облака.
Но насколько эффективно потребляют ресурсы процессы, запущенные внутри кластера? На этот вопрос поможет ответить мониторинг — основной инструмент FinOps. Он позволяет получить детальную аналитику потребления, чтобы проводить бюджетирование, основываясь на реальных цифрах.
В этом выражена мотивация внедрения FinOps. Но то, насколько она сильна, — зависит от команды и зрелости процессов. Можно выделить две основные цели, которые ставят перед собой организации.
- Прогнозирование и подсчет расхода текущих ресурсов. Это помогает понимать и контролировать затраты на облачные услуги.
- Создание культуры принятия экономически обоснованных решений. Подход включает в себя понимание затрат и их влияния на бизнес-модель. На основании этой информации компании могут принимать более взвешенные решения.
Для достижения этих целей FinOps также может включать автоматизацию, процессы управления ресурсами и аллокацию затрат. Все больше компаний используют контейнеры в облаке, поэтому FinOps интегрируется в этот процесс.
Как применить FinOps? Знакомство с OpenCost
С излишними тратами на инфраструктуру часто сталкиваются при масштабировании кластеров Kubernetes. Наладить ситуацию вот уже с 2021 года пытаются разработчики kubecost. Они разрабатывают разные решения, в том числе OpenCost — «инспектор» для мониторинга контейнеров с открытым исходным кодом.
Каждый желающий может сделать вклад в проект, например написать интеграцию со своим облачным провайдером. Сегодня OpenCost нативно работает с AWS, Azure и GCP, то есть может автоматически подгружать и рассчитывать стоимость ресурсов данных облаков. Однако можно также подключить таблицы с ценами для кластеров Kubernetes у собственного провайдера и использовать OpenCost в его «экосистеме».
Ниже — параметры расценки ресурсов, которые предлагают использовать разработчики при работе с облаками без интеграции:
{
"provider": "custom",
"description": "Default prices based on GCP us-central1",
"CPU": "0.031611",
"spotCPU": "0.006655",
"RAM": "0.004237",
"spotRAM": "0.000892",
"GPU": "0.95",
"storage": "0.00005479452",
"zoneNetworkEgress": "0.01",
"regionNetworkEgress": "0.01",
"internetNetworkEgress": "0.12"
}
Набор параметров может отличаться для облака, в котором вы разворачиваете OpenCost. Например, в Managed Kubernetes от Selectel нет zoneNetworkEgress и regionNetworkEgress, а spotCPU и spotRAM пока не актуальны, наша команда разработки занимается вопросом их поддержки.
Впрочем, это не все нюансы, которые стоит учитывать для более точного расчета ресурсов. Разберемся на практике: посмотрим, как развернуть OpenCost на базе кластера Managed Kubernetes в облачной платформе Selectel.
Установка OpenCost в Managed Kubernetes
В целом, инструмент можно развернуть в любом кластере, начиная с Kubernetes 1.8. Сегодня в облаке Selectel доступны все актуальные версии. Выбрать можно любую — для примера развернем свежий Kubernetes 1.29: Mandala.
Создание кластера Managed Kubernetes
Кластер можно легко создать с помощью нашего Terraform-провайдера. Но мы покажем на примере панели управления.
Новость для тех, кто давно не пользовался Managed Kubernetes. Мы упростили создание кластеров. Разбили форму на три простых шага: выбор конфигурации кластера, добавление групп нод и настройка автоматизации.
1. Перейдем в панель управления, откроем раздел Облачная платформа → Kubernetes и настроим кластер.
2. Следующим этапом настроим группы нод.
В параметрах OpenCost для каждого ресурса можно указать только один тип. Если вы используете один тип дисков или GPU, проблем не будет — можно указать стоимость, инспектор ее «съест» и примет в расчет. Но если вы используете два разных диска или GPU, OpenCost не сможет точно посчитать потребление. Это нужно учитывать при выборе конфигурации кластера.
3. Далее настроим процессы автоматизации: автовосстановление и автообновление — и нажмем кнопку Создать.
Готово — спустя пару минут кластер будет создан. Теперь к нему можно подключиться, установить Helm и OpenCost.
Установка и настройка OpenCost
1. Установим Prometheus — он нужен для сбора данных о потреблении ресурсов. Для этого инструмента нужно указать Storage Class или объявить значение по умолчанию.
kubectl get sc
В выводе будет название существующего Storage Class. В нашем случае оно такое:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
fast.ru-2c cinder.csi.openstack.org Delete Immediate true 15m
Используйте данное имя, чтобы задать Storage Class по умолчанию.
kubectl patch storageclass fast.ru-2c -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Установите Prometheus в репозиторий и загрузите его.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts &&\
helm repo update
helm install my-prometheus --repo https://prometheus-community.github.io/helm-charts prometheus \
--namespace prometheus --create-namespace \
--set prometheus-pushgateway.enabled=false \
--set alertmanager.enabled=false \
-f https://raw.githubusercontent.com/opencost/opencost/develop/kubernetes/prometheus/extraScrapeConfigs.yaml
Если имя my-prometheus, порт или namespace поменяются, не забудьте заменить значения в values.yaml, описанном в п.4.
2. Добавим репозиторий opencost-charts в Helm.
helm repo add opencost-charts https://opencost.github.io/opencost-helm-chart &&\
helm repo update
3*. Если планируете публиковать дашборды с потреблением ресурсов в интернет, создайте Ingress Controller и укажите необходимый хост файла values.yaml в п.4.
ingress:
enabled: true
ingressClassName: ""
annotations: {}
hosts:
- host: opencost.example.com
paths:
- /
servicePort: http-ui
tls: []
opencost.example.com — имя вашего домена со значением А-записи облачного балансировщика, который использует Ingress Controller.
4. Создадим файл values.yaml для OpenCost со следующим содержимым:
networkPolicies:
enabled: false
prometheus:
namespace: prometheus
port: 9090
labels:
app.kubernetes.io/name: prometheus
updateStrategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
service:
enabled: true
annotations: {}
labels: {}
type: ClusterIP
extraPorts: []
rbac:
enabled: true
opencost:
cloudIntegrationSecret: ""
exporter:
apiPort: 9003
cloudProviderApiKey: ""
defaultClusterId: 'default-cluster'
image:
registry: quay.io
repository: kubecost1/kubecost-cost-model
tag: ""
pullPolicy: IfNotPresent
fullImageName: null
extraArgs: []
replicas: 1
resources:
requests:
cpu: '10m'
memory: '55Mi'
limits:
cpu: '999m'
memory: '1Gi'
livenessProbe:
enabled: true
path: /healthz
initialDelaySeconds: 120
periodSeconds: 10
failureThreshold: 3
readinessProbe:
enabled: true
path: /healthz
initialDelaySeconds: 120
periodSeconds: 10
failureThreshold: 3
securityContext: {}
extraVolumeMounts: []
env: []
extraEnv: {}
customPricing:
enabled: false
configmapName: custom-pricing-model
configPath: /tmp/custom-config
createConfigmap: true
provider: custom
costModel:
description: Modified pricing configuration.
CPU: 0.9
spotCPU: 0
RAM: 0.33
spotRAM: 0
GPU: 38.4
storage: 0.05
zoneNetworkEgress: 0
regionNetworkEgress: 0
internetNetworkEgress: 0.52
dataRetention:
dailyResolutionDays: 15
cloudCost:
enabled: true
refreshRateHours: 6
runWindowDays: 3
monthToDateInterval: 6
queryWindowDays: 7
prometheus:
internal:
enabled: true
serviceName: my-prometheus-server
namespaceName: prometheus
port: 80
ui:
enabled: true
image:
registry: quay.io
repository: kubecost1/opencost-ui
tag: ""
pullPolicy: IfNotPresent
fullImageName: null
resources:
requests:
cpu: '10m'
memory: '55Mi'
limits:
cpu: '999m'
memory: '1Gi'
uiPort: 9090
livenessProbe:
enabled: true
path: /healthz
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe:
enabled: true
path: /healthz
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
ingress:
enabled: true
ingressClassName: "nginx"
annotations: {}
hosts:
- host: opencost.example.com
paths:
- /
servicePort: http-ui
tls: []
extraContainers: []
extraVolumes: []
Полный список возможных параметров доступен по ссылке.
5. Установим OpenCost через менеджер пакетов Helm с использованием конфигурации values.yaml.
helm install opencost opencost-charts/opencost --namespace opencost --create-namespace -f values.yaml
6. Подождите, пока поды OpenCost перейдут в состояние Ready. Статус можно проверить с помощью команды:
kubectl get pods -n opencost -w
7. Выполняем запрос к веб-странице по нашему домену — например, opencost.example.com — в браузере. На этом этапе вы должны увидеть интерфейс инспектора.
Примечания
1. Если необходимо обезопасить доступ к данным, в поле extraContainers конфигурации values.yaml можно добавить дополнительный контейнер, который будет проксировать запросы на сервер авторизации. Пример доступен по ссылке.
2. По умолчанию валюта выбирается в долларах (USD), но ее можно изменить в правом верхнем углу на RUB. Или использовать специальную ссылку, чтобы потребление сразу отображалось в рублях. Вот так:
http://opencost.example.com/?currency=RUB
3. Стоимость ресурсов кластера задается в customPricing.costModel конфигурации values.yaml. В нашем примере указаны цены для быстрого SSD и Tesla T4. Стоимость ресурсов облачной платформы Selectel указана в рублях для пула ru-2. Значения также можно задать через ConfigMap с ценами ресурсов и указание его в values.yaml. О том, как это сделать, написано в документации.
OpenCost на практике: тестирование с нагрузкой
Попробуем проверить, как поведет себя OpenCost, если на кластер оказать дополнительную нагрузку.
В только что созданном кластере «все спокойно». Можно посмотреть, какие процессы оказывают большую нагрузку и сколько она стоит в рублях.
Окажем небольшую нагрузку на тестовое веб-приложение в соседнем пространстве имен (web-test-app) и посмотрим, как OpenCost оценит эффективность загрузки ресурсов.
Получились следующие результаты по запущенным процессам и потреблению вычислительных ресурсов:
Метрики можно частично проверить в выводе kubectl top pod -A. Видим, что пространство имен web-test-app действительно забирает большую часть по CPU в кластере:
На графике выше также видно, сколько процессы потребляют в денежном эквиваленте. О том, как все это считается, можно прочитать в официальной документации OpenCost.
Оптимизация потребления ресурсов
Теперь, когда вы знаете, сколько ресурсов потребляют установленные приложения, можно заняться оптимизацией. Для этого нужно посмотреть данные мониторинга и понять, какие ресурсы используются кластером не в полной мере. И при необходимости изменить конфигурацию на попроще, но которой будет достаточно.
Подберите оптимальную конфигурацию
Обсудим на примере видеокарт. Для начальных задач необязательно брать самые топовые видеокарты. Та же GTX 1080 до сих пор актуальна в задачах инференса — наравне с T4 и A2000. CUDA-ядер меньше, но зато они все используются вашим кластером, а вы — не переплачиваете.
В тот же момент, если вы планируете одновременно запускать несколько инстансов на одной видеокарте, нужно выбирать GPU с возможностью шеринга на партиции. Тогда выбор ограничивается видеокартами, которые поддерживают технологии TimeSlicing или MIG.
Сократите потребление сети
Оцените, как много данных сети использует ваш кластер. Все ли необходимо загружать через сеть? Или лучше один раз их загрузить, кэшировать и сэкономить на трафике?
Эти вопросы особенно актуальны, если вы работаете с большими объемами данных, например дата-сетами, и постоянно их скачиваете или загружаете в облако. На этом процессе можно не только сэкономить бюджет, но и время, настроив кэширование данных в кластере. В облаке Selectel предоставляются 3 ТБ внешнего трафика бесплатно, но если его больше, то такая аналитика может быть особенно полезна.
Освобождайте неиспользуемые ресурсы
Если вы работаете с большим количеством оперативных задач — например, тестированием приложений — настройте утилизацию вычислительных ресурсов. Это могут быть неактивные поды, устаревшие реплики, остаточные логи и даже полноценные процессы, которые не видны, но фоново работают в состоянии простоя.
С такой проблемой столкнулись и мы, когда настраивали тестирование микросервисов на базе OpenStack. О том, как нам удалось утилизировать остаточные ресурсы, рассказали в отдельной статье.
Что нужно учитывать
В нашем случае OpenCost хорошо подходит для оценки эффективности потребления ресурсов в кластере, но не более. Почему так? Давайте разбираться.
Мы выше уже говорили, что при формировании values.yaml можно указать только один тип диска и GPU. Однако есть еще несколько ограничений, связанных с расчетом потребления.
- OpenCost не учитывает стоимость балансировщика, Managed Kubernetes как услуги, дисков самих воркер-нод и публичных IP-адресов. Это связано с тем, что они являются сущностями облачной платформы, а не кластера, в котором развернут инспектор. Этот вопрос могла бы легко решить полная интеграция OpenCost с API облака Selectel.
- OpenCost считает стоимость балансировщика через стоимость пройденного через него трафика, что неверно, так как она фиксирована. То есть, если взять проект облачной платформы, в котором нет ничего кроме кластера, все равно не получится посчитать полную сумму за потребление. Опять же, это решается интеграцией с нашим API.
Проще говоря, широкий выбор конфигураций в Managed Kubernetes — это как преимущество, так и некий «ограничивающий фактор» для OpenCost, когда он пытается посчитать потребление ресурсов.
Разумеется, все расходы можно посмотреть в панели управления, в том числе — потребление ресурсов нодами кластера. Однако инструменты вроде OpenCost отлично дополняют статистику и помогают анализировать расходы на уровне отдельных процессов, запущенных в кластере.