Kubernetes — самый популярный оркестратор в России. По данным исследования VK Cloud «State of Kubernetes», K8s используют 56% компаний, работающих с оркестраторами (причем из них 53% работают с Kubernetes в облаке). Более того, спрос на работу с технологией увеличивается. Вместе с тем многие компании сталкиваются с недостатком опыта, что приводит не только к техническим сложностям, но и к неоправданным расходам.
Рассказываем, почему работа с Kubernetes может оказаться «тяжелой ношей» для бюджета компании и как этого избежать.
Жизнь до Kubernetes: начнем сначала
Kubernetes (K8s) ориентирован на работу с большим числом хостов и контейнеров. Соответственно, для K8s больше подходят приложения со слабосвязанной микросервисной архитектурой и четкими границами модульности, которые можно независимо деплоить, разрабатывать и масштабировать.
Здесь все очевидно: микросервисы удобнее упаковывать в отдельные контейнеры для последующего управления через k8s. В случае с монолитной архитектурой получить корректное дробление компонентов приложения на контейнеры невозможно.
Из этого можно сделать два вывода.
Если приложения еще нет, при разработке лучше сразу делать его микросервисным. Так можно обеспечить полную совместимость приложения с Kubernetes «из коробки» без необходимости использования «костылей» или глобальных переработок на уровне архитектуры. При разработке микросервисного приложения желательно взять за основу «золотой» стандарт The Twelve-Factor App — в нем собраны основные рекомендации по поводу методологии разработки кода, зависимостей, работы с внешними сервисами, администрирования и других моментов, с которыми придется столкнуться. Особенное внимание стоит обратить на рекомендации, которые помогают изначально избежать переплаты. Например, собирайте контейнеры по принципу минимальной необходимости — это поможет экономить на registry; используйте облачные PaaS-сервисы — это позволит экономить на администрировании и времени разработки; проводите нагрузочные тесты — это даст возможность задействовать ресурсы оправданно.
Если приложение есть, но с монолитной архитектурой — его придется дробить на микросервисы. В результате должна получиться слабосвязанная архитектура, где каждая функциональность будет состоять из отдельных сервисов и будет контейнеризирована вместе с зависимостями. Очевидно, что в таком случае изменения затронут не только дизайн архитектуры, но и код приложения, то есть это долгий и ресурсоемкий путь. Здесь поможет небольшой лайфхак: не обязательно разворачивать в Kubernetes сразу всё приложение — можно часть сервисов развернуть в K8s, а монолитную часть оставить за пределами оркестратора.
Теперь подробнее о том, в каких ситуациях Kubernetes может стать «дорогим удовольствием» и как этого избежать.
Все кейсы и рекомендации приведены в контексте работы с Kubernetes в облаке — 53% компаний, работающих с оркестратором, выбирают именно эту среду. Но они также применимы и при работе с K8s на других платформах.
Причины «утечки денег» на уровне архитектуры и способы их устранения
Нередко причины нерационального потребления ресурсов и, как результат, дополнительных расходов обусловлены незнанием или непониманием встроенных механизмов K8s. Рассмотрим типичные проблемы этого «уровня» и способы их решения.
Отсутствие автомасштабирования
Зачастую приложения работают не с постоянной, а динамической нагрузкой. При этом, чтобы стабильно выдерживать пики нагрузок, разработчики иногда резервируют и держат активными большие массивы мощностей. Такой подход ошибочен, ведь даже за простаивающие, но активные мощности надо платить (в случае работы на своем «железе» — еще и тратить деньги на покупку оборудования). То есть работа с фиксированным массивом подов неэкономична.
Best practice в данном случае является использование горизонтального автомасштабирования мощностей с помощью HorizontalPodAutoscaler (HPA).
HPA — функция автомасштабирования в K8s, которая автоматически увеличивает или уменьшает количество развернутых (активных) подов (контейнеров) в зависимости от текущей нагрузки. С помощью HPA можно автоматизировать управление как ЦП, так и памятью.
Таким образом, использование HPA избавляет от необходимости держать активными ненужные мощности и нерационально расходовать на них бюджет: простаивающие поды будут автоматически отключаться, а новые — добавляться лишь тогда, когда они действительно нужны.
Использование постоянного числа worker-групп
Один из самых «прожорливых» потребителей ресурсов в K8s — рабочие группы. Соответственно, как и в случае с подами, держать их включенными без нагрузок — прямой путь к быстрому и неэффективному расходованию бюджета.
В данной ситуации на помощь также приходит автомасштабирование рабочих групп, которое работает в паре с HPA.
Логика работы такой «связки» простая и очевидная:
при уменьшении нагрузки HPA автоматически снижает количество контейнеров в рабочем процессе приложения;
если нагрузка продолжает снижаться — снижается количество нод в нод-группе.
Тут важно отметить, что для корректной работы автомасштабирования важно ограничить максимальное количество масштабируемых нод. Если этого не сделать, в случае утечки по памяти или DDoS-атаки мощности будут добавляться ошибочно, повышая расходы.
Подробнее о том, как настраивать масштабирование узлов кластера, можно почитать здесь.
Использование только выделенных мощностей
При работе с K8s довольно часто могут возникнуть временные или даже разовые задачи. Также в приложении могут использоваться stateless-сервисы, которым не надо сохранять состояния. Без должного опыта или при наличии больших бюджетов под такие нагрузки могут задействоваться выделенные мощности, которыми полностью управляет клиент облака.
Но это не всегда оправданно: для временных или некритических нагрузок рациональнее использовать Spot-instances, то есть неиспользуемые в данный момент облачным провайдером экземпляры ВМ.
Главное преимущество такого подхода в том, что скидки на Spot-instances могут достигать 90%. Но есть и обратная сторона медали: надежность таких инстансов не гарантируется, потому что провайдер может их отключить в любой момент, если ему понадобятся эти мощности.
Впрочем, при правильном управлении Spot-instances их можно эффективно использовать в разных сценариях, существенно сокращая расходы.
Неправильная работа с данными
Работа приложения неразрывно связана с необходимостью обработки и хранения большого объема разноформатных данных. Если оставлять все файлы в контуре оркестратора, K8s рискует превратиться в «неповоротливое» и дорогое хранилище. С точки зрения экономии это явно не лучший сценарий.
Лучшей практикой при работе с Kubernetes является хранение больших массивов данных в S3-хранилище — оно медленнее, но зато кратно дешевле и вместительнее.
Что особенно важно, построить связку Kubernetes и S3-хранилища в облаке довольно просто. Например, в облаке VK Cloud для этого даже не нужны дополнительные коннекторы и сложные реализации — всё можно настроить в несколько кликов.
Об экономии на уровне «куба»
С утечками бюджета на уровне приложения архитектуры разобрались, а теперь к самому Kubernetes. Здесь все несколько проще, поскольку в K8s есть встроенные механизмы оптимизации — достаточно в них разобраться и начать их использовать.
Назначение лимитов
В Kubernetes есть механизм лимитов (limits) и реквестов (requests) — с их помощью можно назначить, сколько ресурсов может использовать каждый контейнер. Лимит — максимальное значение, которое нельзя превышать. Реквесты — наименьшее количество ресурсов, которое должно быть доступно контейнеру.
В контексте сокращения расходов важно именно значение лимитов — если его не задать, в случае «утечки» по памяти контейнер будет разрастаться неоправданно сильно и оккупировать все доступные ресурсы.
Фактически назначение лимитов дает возможность регламентировать потребление мощностей и предотвратить расходы на оплату мощностей в облаке, которые на самом деле не нужны.
Одна из ключевых сложностей здесь — правильно назначить лимиты. Если их излишне занизить, приложение просто упадет при пиковых нагрузках или будет работать недостаточно эффективно. Поэтому, чтобы не допустить ошибку на этом этапе, лучше использовать специальные приложения для расчета лимитов вроде Robusta или Katalyst.
Назначение квот ресурсов
Работа с квотами несколько напоминает работу с лимитами — здесь также можно контролировать использование ресурсов, но уже для каждого namespace (пространства имен). То есть с помощью квот можно ограничить, сколько именно пользователь или группа пользователей смогут использовать ресурсов в кластере K8s.
Поскольку есть четкая связь «объем потребляемых ресурсов = деньги», последствия игнорирования такой практики очевидны: можно столкнуться с неоправданным перерасходованием мощностей на уровне namespace и сильно выйти за пределы предполагаемых бюджетов.
Разберем алгоритм работы с квотами на простом примере.
Создаем namespace с помощью команды
kubectl create namespace <namespace-name>
.Создаем квоту ресурсов с помощью команды
kubectl create quota <resource-quota-name> --hard=<cpu-limit>cpu,<memory-limit>memory --namespace=<namespace-name>
.Назначаем квоты с помощью команды
kubectl create quota my-quota --hard=3cpu,3Gi --namespace=my-namespace.
Здесь квота с лимитом на 3 CPU и память в 3Gi.Создаем предельный диапазон, используя команду
kubectl create -f <limit-range-definition-file> --namespace=<namespace-name>
.Применяем квоту и предельный диапазон, добавляя в YAML модуля аннотацию
quota.openshift.io/my-quota: "true" limits.cpu: "3" limits.memory: "3Gi"
.
Установленные квоты можно посмотреть с помощью команды kubectl describe quota --namespace=<namespace-name>
.
Определение размера нод
Правильность расчета размера ноды напрямую влияет на эффективность расходования бюджета. Тут все просто: размер ноды определяет, сколько подов на ней можно разместить. Если поды потребляют, например, только 50% ресурсов ноды, то оставшиеся 50% будут простаивать, но платить за них придется. Поэтому с точки зрения экономии важно, чтобы размер ноды учитывал потенциальную нагрузку.
Принцип расчета и подробные рекомендации, как правило, предлагают облачные провайдеры — например, это подробно описано в технической документации VK Cloud. Но упрощенно подход следующий:
если приложению надо много ресурсов, но оно не всегда активно используется, лучше выбирать большие ноды — в таком случае будет достаточный запас мощностей для пиковых нагрузок;
если приложению надо мало ресурсов, но оно работает постоянно, то больше подойдут ноды меньшего размера — в таком случае ресурсы будут утилизироваться эффективнее.
Отключение и удаление ненужного
При работе с K8s довольно часто встречаются сценарии, при которых мощности нужны временно — например, для тестов или небольших временных задач. Нюанс в том, что нередко даже под такие кейсы выделяются поды и кластеры, которые после использования остаются активными. Дальше все очевидно: тест прогнали, кластер остался активным, деньги за выделенные ресурсы списываются, бюджет заканчивается.
Предотвратить подобные сценарии просто — достаточно ввести практику остановки кластеров и подов в момент длительного простоя. Экономия будет значительной — после остановки тарифицироваться будут только диски, а не все мощности ВМ.
При этом, естественно, предварительно надо проверить, что отключение кластера или пода не скажется на dev-, stage- и prod-среде.
С «мусором» на кластерах и подах сходная ситуация. Ресурсы кластера и пода ограниченны, и задействовать их под размещение ненужных тестовых приложений или старых метаданных — не лучшая практика, поскольку бюджет будет расходоваться фактически на хранение «хлама». Причем проблема действительно может быть весомой: постепенное накопление «мусора», потребляющего даже незначительный объем ресурсов, в итоге может привести к ощутимому перерасходованию мощностей и нерациональному масштабированию кластеров.
Таким образом, регулярная зачистка кластеров и подов от «мусора» — отличная возможность сократить расходы. Причем для этих задач можно подключить автоматические функции вроде автоматического удаления метаданных.
Важный лайфхак
Часто сразу увидеть экономический эффект от проводимой оптимизации невозможно — на это нужны дни, недели или даже больше. Но такое движение «вслепую» не всегда оправданно — иногда можно отказаться от нужных возможностей ради экономии «на копейку».
Избежать подобных факапов и получить полную картину влияния действий на экономический эффект можно с помощью специальных инструментов мониторинга и наблюдения, таких как OpenCost.
OpenCost — Open-Source-сервис для контроля расходов в Kubernetes и облачных средах. С его помощью можно отслеживать прошлые и текущие затраты на K8s и облако, а также распределение ресурсов. Причем инструмент дает подробную «разбивку» расходов по кластерам, узлам, namespaces, контроллерам, подам, сервисам.
При работе с подобными решениями «слепые зоны» проводимой оптимизации исчезают — можно сразу видеть, какие процессы и как потребляют ресурсы и насколько сокращаются расходы в результате проводимых манипуляций на уровне архитектуры и Kubernetes.
Вместо выводов
Направить расходы при работе с Kubernetes в «правильное русло» — проще, чем кажется, если знать, где экономить. Еще больше об этом вы можете узнать из нашего вебинара «Как работать с Kubernetes и не тратить лишнего?», в котором мы рассказываем про «золотой стандарт» The Twelve-Factor App, мониторинг и автомасштабирование. Всё это подкреплено примерами работы с K8s в VK Cloud — там вы можете сразу применить всё на практике.
Узнавайте о новых релизах, вебинарах и выходящих статьях в Telegram-канале Tarantool News.
Задать вопросы команде разработчиков про использование Tarantool можно в официальном канале сообщества.
О принципах и примерах работы продуктов Tarantool читайте в блоге на сайте.