Я Олег Одинцов, платформенный инженер App.Farm. App.Farm — собственная разработка Россельхозбанка, которая используется для стандартизации процессов разработки программного обеспечения и предоставления высокоуровневого интерфейса пользователям для автоматизации их задач. Можно сказать, что App.Farm — это автоматизация «под ключ». Пользователь получает полный цикл управления разработкой от размещения кода до деплоя приложений. Более «смузийное» название — IDP платформа.

В этом материале расскажу, как мы управляем жизненным циклом нашей платформы. Пользователи взаимодействуют с платформой через API или через веб-интерфейс и не знают, что происходит у платформы под капотом. Долгое время нам приходилось создавать ручные заявки в сервис-деске для получения доступа к виртуализации, это могло длиться до двух недель. Платформа росла, и в неё стали «заезжать» критичные системы для бизнеса. Тогда от бизнеса пришла задача — реализовать катастрофоустойчивое размещение 89 сервисов в нашей платформе, а это — Свои финансы (ДБОФЛ), Свой бизнес (ДБОЮЛ), Цифровой офис сотрудника (ЦОС), весь AML-стек и многое другое. А еще в банке шел процесс импортозамещения, и мы получили беспрепятственный доступ к виртуализации. У нас «развязались» руки.
Как нам готовить виртуальную машину (VM)? Раньше этим занимался другой отдел. Как нам разворачивать кластеры Kubernetes? Как много нам готовить кластеров? Наша платформа состоит из множества кластеров, каждый из которых выполняет свои задачи. Мы стали формировать требования для инструмента, который будет решать задачу катастрофоустойчивости: он должен быть сопровождаем как код, должен быть модульным, чтобы можно было его дорабатывать и легко тиражировать.
Мы исследовали рынок и остановили свой выбор на двух инструментах — Terraform и Cluster Api, составили таблицу для сравнения, выделили важные для нас критерии. Ключевое отличие — в Cluster API управление инфраструктурой происходит через объекты Kubernetes, то есть ты деплоишь объекты Cluster API и на основе этих объектов создается кластер kubernetes.В случае Terraform происходит декоративное описание через HCL.
Важным критерием для нас было то, поддерживает ли инструмент такой паттерн, как reconciliation loop. Cluster API его предоставляет, Terraform — нет. И для себя мы сформировали ещё один критерий: нам бы хотелось инструмент, при помощи которого мы будем не просто создавать VM, но и делать из VM kubernetes ноду. И опять же в Cluster API это можно сделать, в Terraform нельзя.
По всем критериям нам идеально подходил Cluster API. Но не все было так гладко, потому что перед нами стояла задача катастрофоустойчивости, которую нужно было успеть сделать в жесткие сроки. Если бы мы взялись за Cluster API, то не смогли бы гарантировать бизнесу, что успеем в сроки. Муки выбора привели нас к следующему решению: мы поделились на две команды. Одна команда делала решение через Terraform, потому что она могла гарантировать, что за отведенные сроки решит эту задачу. А вторая команда пошла исследовать Cluster API, так как нам очень сильно хотелось его использовать.
Построение платформы с использованием Terraform: наш опыт
Когда мы начали работу над проектом, думали, что все будет достаточно просто. Terraform — это уже известный инструмент, который давно присутствует на рынке. Мы считали, что найдем уже готовые модули под наши требования, однако реальность оказалась куда более сложной.
Нам нужна была не просто кластерная система, а целая платформа, которая бы соответствовала нашим специфическим нуждам.
К сожалению , нам достался Terraform-провайдер со скудным функционалом — в нем были баги и отсутствовал необходимый функционал, поэтому нам пришлось его форкнуть и доработать.
Поскольку не было готовых terraform модулей, мы решили разработать собственную архитектуру модулей Terraform и доработать работу существующего провайдера, включая исправление багов и добавление необходимых функций, что дало нам возможность адаптировать платформу под наши нужды.
На схеме, которую мы разработали, показана наша архитектура модулей. Если смотреть снизу вверх, то базовыми кирпичиками являются объекты instance и disk. На основе этих кирпичиков создаются модули KubeNode и InstaCluster. KubeNode описывает ВМ для kubernetes, со всеми необходимыми дисками и сетями.
Далее на основе KubeNode формируется модуль KubeCluster, который описывает кластер kubernetes. Поскольку на платформе нам нужны не только ноды для kubernetes, но и дополнительные ноды для поддержки BGP и DNS, мы разработали модуль Instacluster.
Совместив эти два модуля, мы получили модуль App.Farm, который представляет собой полное описание нашей платформы. Таким образом, через один tfvars файл мы можем описывать всю нашу платформу, что значительно упрощает процесс ее тиражирования.
На данный момент мы реализовали все это через Terraform и написали код на DSL (Domain-Specific Language). В дальнейшем мы можем перенести эту реализацию на язык программирования.
В итоге нам удалось успешно завершить проект с использованием Terraform. Мы получили декларацию наших кластеров, быстрое и масштабируемое описание платформы. Добавление нового кластера стало легким и быстрым процессом — теперь нам не нужно ждать три недели для обработки заявки. Благодаря тому, что у нас появилась возможность описывать нашу платформу через Terraform, мы смогли мгновенно реагировать на изменения и потребности проекта.
Наш опыт показал, что создание платформы с использованием Terraform требует глубокого понимания как самого инструмента, так и специфики вашего проекта. Однако результаты стоят затраченных усилий — мы создали эффективное решение, которое отвечает всем нашим требованиям и позволяет быстро развиваться в будущем.
Cluster API: погружение в технологию
Хотя мы и решили все задачи проекта, напомню, что мы очень сильно хотели использовать Cluster API. Расскажу, что нам удалось исследовать в этой области и что мы реализовали. Cluster API — это инструмент для создания Kubernetes-кластеров. На первый взгляд, кажется, что всё просто: создаёшь CR (Сustom Resource), и кластеры создаются автоматически. Однако на практике оказывается всё гораздо сложнее.
Архитектура Cluster API делится на две основные части. Первая часть — это Control Plane, который разворачивается в управляющем Kubernetes-кластере. Чтобы воспользоваться Cluster API, необходимо сначала установить его в первоначальный Kubernetes-кластер, куда будет задеплоен Control Plane Cluster API и в котором будут создаваться объекты.
Вторая часть — это workload кластера, который является результатом работы Cluster API. Workload может развертываться в облачных средах или системах виртуализации. Поддерживаются известные облака, такие как Amazon, Azure и Google, а также системы виртуализации, включая VMware и OpenStack. Если готового провайдера для вашей виртуализации нет, его можно написать самостоятельно. У Cluster API отличная документация, которая поможет вам разобраться с необходимыми компонентами для реализации собственного провайдера. Мы также прошли этот путь и успешно создали свой.
Теперь давайте более подробно рассмотрим процесс создания кластера на примере конкретной ноды. Провайдеры Cluster API являются основой Control Plane, состоят из четырех ключевых компонентов. Первый провайдер называется core-capi. Его иногда называют просто core-capi или capi, но я предпочитаю первое название, так как оно более чётко выделяет его роль. Core-capi — это основной провайдер, который обрабатывает ресурсы кластера, на выходе которых получается workload кластера.
Infrastructure Provider играет важную роль в процессе создания и настройки кластеров. Этот провайдер взаимодействует с API виртуализации, создавая ноды, которые затем преобразуются в полноценные Kubernetes-узлы. Среди готовых провайдеров Infrastructure Provider можно выделить решения для популярных облачных платформ, таких как AWS, Azure и Google Cloud. Если вы хотите протестировать функциональность Cluster API локально, существует отличный провайдер — Docker. Он использует Docker-контейнеры в к��честве API виртуализации, что позволяет легко понять, как работает система.
Другим важным компонентом является Bootstrap Provider. Этот провайдер отвечает за подготовку конфигурации Cloud-init, необходимой для превращения ноды в Kubernetes-узел. Один из рекомендуемых Cluster API провайдеров — это Kubeadm Provider, который обеспечивает эту функциональность.
Также стоит упомянуть Controlplane Provider, который управляет жизненным циклом мастер-нод. Он отвечает за добавление, удаление и поднятие мастер-узлов, что критически важно для стабильной работы кластера.
Теперь давайте рассмотрим процесс создания ноды более подробно. Для этого нам необходимо создать несколько объектов, чтобы успешно развернуть кластер с помощью Cluster API.
Когда я начал изучать Cluster API и тестировать его возможности, у меня было предположение, что каждый провайдер обрабатывает свои собственные ресурсы. Например, ресурс кластера описывает сам кластер и обрабатывается core-capi для создания необходимых ресурсов. InfraMachineTemplate является шаблоном виртуальной машины, на основе которого создается объект InfraMachine — это уже непосредственно нода в нужной виртуализации.
Кроме того, Bootstrap-config template служит шаблоном конфигурации для ноды, а Contraplane template — шаблоном для мастер-нод. Однако на практике оказалось, что все эти объекты, необходимые для создания workload-кластера, обрабатываются core-capi. Развернуть кластеры и управлять ими у нас не получилось. В следующей главе опишу правильный алгоритм создания workload-кластера.
Процесс создания ноды с помощью Cluster API
Теперь я расскажу, как правильно создавать ноды в Kubernetes с использованием Cluster API (CAPI). Когда такие объекты, как Machine, InfraMachine и BootstrapConfig, уже созданы, провайдер CAPI назначает объект Machine владельцем (owner) для двух этих ресурсов. В этот момент начинается активное взаимодействие между различными провайдерами.

Bootstrap Provider следит за состоянием BootstrapConfig и ожидает, пока у него появится владелец. Как только это происходит, запускается логика, которая создает секрет, содержащий конфигурацию CloudInit. Этот секрет необходим для того, чтобы объект Machine стал полноценной Kubernetes-нодой. После этого происходит патчинг объекта Machine, который связывает его с созданным секретом.

В то же время Infrastructure Provider также отслеживает объекты InfraMachine и Machine. Как только объект Machine связывается с секретом и у объекта InfraMachine появляется владелец, Infrastructure Provider инициирует процесс создания ноды. Он обращается к API виртуализации и создает ноду на основе предоставленных данных.

После успешного создания ноды Infrastructure Provider подставляет в неё конфигурацию из секрета, и таким образом, нода становится частью кластера Kubernetes. Этот процесс идентичен как для worker-нод, так и для master-нод. Разница заключается лишь в том, что объект Machine для worker-нод создается через core-capi, а для master-нод — через Contraplane Provider.

Таким образом, процесс создания ноды с помощью Cluster API выглядит следующим образом: сначала создаются необходимые объекты, затем происходит их связывание и последующее обращение к API виртуализации для создания ноды.
В результате нашего исследования нам удалось полностью реализовать собственный провайдер для нашей виртуализации, так как готового решения не существовало. Мы разработали объект OvirtMachine, который описывает нашу машину для нашей виртуализации. Это позволило нам подготовить тестовое решение для создания виртуальных машин.

В дальнейшем мы планируем полностью перейти на использование Cluster API и отказаться от Terraform, управляя жизненным циклом нашей платформы через этот мощный инструмент.
Другие статьи про App.Farm:
● Как мы создавали PaaS‑платформу App.Farm
● App.Farm CI. Часть I. Проблемы и выбор решений
● App.Farm CI. Часть II. Конвейер — швейцарский нож: особенности запуска мультиарендного процесса разработки
● App.Farm CI. Часть III. Подготовка к реализации flow — быть вахтером или не быть?
● App.Farm CI. Часть IV. Реализуем flow — шагаем к автоматизации разработки
● Когда CI заботится не только о коде, но и о пользователях. App.Farm CI. Часть V

