Автоматизация управления ресурсами окружений в Dev Platform
При работе с облачной инфраструктурой важна не только гибкость использования ресурсов, но и возможность автоматизировать основные рутинные процессы. При разработке своих продуктов мы в команде VK Tech стараемся следовать именно этим принципам. В нашем продукте Dev Platform в рамках одной из возможностей реализовано автоматическое управление инфраструктурными ресурсами, необходимыми для разработки программного обеспечения — например, виртуальными машинами, Kubernetes-кластерами и прочими.
Меня зовут Виктор Горячкин. Я старший разработчик Dev Platform в VK Tech. В этой статье я расскажу о разработанном нашей командой решении для автоматизации развертывания инфраструктуры.
Материал подготовлен по мотивам моего доклада на IT-бар Community.
Знакомство с Dev Platform
Чтобы лучше понять, зачем мы решали описанные в статье задачи, погрузимся в контекст продукта.
Dev Platform — готовое решение для построения внутренних платформ разработки. Платформа позволяет перенести весь цикл создания приложений в единое пространство, повысить эффективность и удобство рабочих процессов, а также обеспечить безопасную разработку программного обеспечения.
Платформа предоставляет пользователям следующие возможности:
Единый портал для разработки приложений со всем необходимым инструментарием. Все инструменты в рамках платформы предустановлены, интегрированы и настроены.
Централизованная ролевая модель, SSO, аудит событий. С помощью решения можно гибко управлять безопасностью, используя централизованную ролевую модель, SSO, аудит событий, библиотеки шаблонов IaC и CI/CD pipelines.
Безопасная разработка. Dev Platform позволяет настраивать интеграцию со многими внешними решениями, в том числе с инструментами безопасной разработки. Например, с продуктами Positive Technologies: Black Box, Container Security и Application Inspector.
Управление ресурсами окружений. Через платформу можно управлять ресурсами для различных сред (dev, test, stage, prod), которые команды будут использовать для отладки и тестирования разрабатываемых приложений, а также для эксплуатации в продуктиве. Именно о данном компоненте речь в данной статье.
Интеграция с VK Cloud. Благодаря интеграции с VK Cloud пользователи платформы получают возможность разворачивать любые ресурсы, доступные в облаке.
Предпосылки
Одна из задач IDP — обеспечить возможность развертывания разрабатывания ПО последовательно в различных сегментах (от тестового до продуктивного). А для этого необходимо, чтобы эти сегменты образов были развернуты и настроены. Таким образом, чтобы добавить в платформу возможность автоматического развертывания инфраструктуры из платформы в облаке, необходимо решить две задачи:
Интегрировать Dev Platform с VK Cloud (в нашем случае).
Реализовать автоматическое развертывание инфраструктурных ресурсов в VK Cloud.
О решении этих задач мы и поговорим в этой статье. Начнем с интеграции платформы и облака.
Часть 1. Интеграция Dev Platform с VK Cloud
Окружения и облако
Прежде чем пойти дальше, давайте разберемся с базовыми сущностями и тем, как и почему они между собой связаны.
Окружения
Окружения — абстракция внутри платформы, предназначенная для объединения инфраструктурных ресурсов. Ресурсы каждого конкретного окружения используются для развертывания на них приложений, которые разрабатываются пользователями платформы. Все, кто связан с разработкой, так или иначе сталкивались с окружениями.
По типу нагрузки и выполняемых задач окружения глобально делят на:
dev — среда разработки;
stage — среда отладки;
test — среда тестирования;
prod — основное окружение, в котором продукт доступен пользователям.
Среды разных типов чаще всего изолированы между собой, но обычно имеют схожую архитектуру — это позволяет двигать разрабатываемое ПО между средами без необходимости доработок или изменений.
Облако
Следует уточнить, что в статье мы говорим про конкретное облако — VK Cloud. VK Cloud базируется на технологии OpenStack. Мы разберем устройство очень поверхностно, получить более подробную информацию об устройстве OpenStack можно на официальном сайте — https://www.openstack.org.
Глобально облако состоит из двух частей:
Control plane — управляющая плоскость, в которой находятся все компоненты, необходимые для работы облака.
Data plane — плоскость данных, в которой находятся ресурсы и сущности, созданные пользователями облака.
Чтобы пользователи не видели ресурсов друг друга в Data Plane, их необходимо изолировать друг от друга. Для этого они разделены на отдельные облачные проекты — у каждого клиента свой, что обеспечивает мультитенантность, где тенант в данном случае — это облачный проект.
В рамках своего облачного проекта пользователи могут разворачивать любые ресурсы, доступные в облаке — например, виртуальные машины, сети, роутеры, Kubernetes-кластеры, базы данных и другие.
Интеграция платформы и облака
Так как все инфраструктурные ресурсы окружения должны разворачиваться в облачном проекте пользователя, перед нами встала задача интеграции платформы и облака, чтобы в дальнейшем мы могли связать конкретное окружение с конкретным облачным проектом пользователя.
Чтобы связать Dev Platform и облако, мы добавили возможность создания интеграций, или Service connections. Для создания интеграции пользователю необходимо указать сервис, с которым он хочет интегрироваться, и заполнить необходимые параметры, которые зависят от интегрируемого сервиса. На данный момент доступна интеграция только с VK Cloud, но в будущем список будет расширяться.
После того как интеграция с облаком успешно создана, пользователь получает возможность выполнять автоматическое развертывание инфраструктуры, о чем мы и поговорим дальше.
Часть 2. Автоматизация развертывания инфраструктурных ресурсов
Для автоматизации развертывания инфраструктуры после анализа существующих и доступных подходов мы решили использовать Terraform. Наш выбор в пользу этого инструмента во многом обусловлен тем, что Terraform — популярное и эффективное решение, с которым работают многие компании. Это связано с его удобством, большим количеством открытой документации и активным комьюнити. К тому же у VK Cloud есть свой Terraform-провайдер.
Немного о Terraform
Terraform — ПО для управления ресурсами, реализующее модель Infrastructure as Code. То есть с Terraform пользователю достаточно определить желаемое состояние инфраструктуры в файле конфигурации, после чего инструмент автоматически создает, изменяет или удаляет ресурсы, чтобы достичь целевого состояния.
У Terraform три основные команды.
Plan — создает план выполнения, где можно посмотреть изменения, которые будут сделаны в инфраструктуре.
Apply — выполняет ранее спланированные действия.
Destroy — удаляет созданные объекты.
Можно выделить пару важных нюансов Terraform.
Terraform позволяет передавать переменные при выполнении apply. Они могут как содержаться в файле, так и быть введены вручную при запуске. В итоге, например, имеющуюся конфигурацию виртуальной машины можно легко адаптировать под новые задачи без необходимости создания новой конфигурации.
Terraform хранит стейт, благодаря которому можно узнать, какие ресурсы развернуты в облаке, если их никто не удалил вручную.
Terraform as a Service
Вместе с тем чистого Terraform для наших задач было недостаточно. Мы стремились к автоматизации, при которой пользователю не придется выполнять преднастройку Terraform вручную. Соответственно, нам был нужен Terraform as a Service.
При этом мы хотели, чтобы Terraform as a Service решал несколько задач:
предоставлял API для выполнения команд plan, apply, destroy;
отвечал за хранение стейта и возможность его получить;
обеспечивал поддержку передачи переменных и поддержку output;
брал на себя задачи авторизации в VK Cloud;
позволял повторно выполнять операции в случае сбоев в инфраструктуре.
Для получения Terraform as a Service мы выбрали один из компонентов магазина приложений VK Cloud, который называется HoE, что в переводе означает «тяпка». Такое название выбрали, потому что terra в слове Terraform — это «земля» и в связи с этим названия сервисов маркетплейса связаны с земледелием. Несмотря на то что у сервиса есть ряд ограничений, которой нам не позволяет использовать его с другими Cloud-провайдерами, на данном этапе он подходит для решения поставленных задач:
предоставляет API для выполнения apply/plan/destroy;
хранит конфигурации Terraform;
дает возможность задавать переменные, получать Output и State;
реализует повторное выполнение операций в случае неудачной попытки, если это необходимо;
берет на себя все вопросы по интеграции с VK Cloud.
В будущем, скорее всего, нам потребуется разработать свое решение для запуска Terraform, чтобы уметь работать не только с VK Cloud.
Теперь, когда у нас появился Terraform as a Service, мы приступили к реализации функциональности управления ресурсами окружений. Стоит отметить, что мы не сразу пришли к решению, которое используется сейчас, поэтому ниже будет описана небольшая история развития фичи.
Итерация 1: Cloud Terraform
После внедрения Terraform as a Service в платформу нам предстояло выстроить обвязку вокруг сервиса, чтобы пользователь мог удобно его использовать.
В качестве референса мы взяли Cloud Terraform от Hashicorp, который адаптировали под себя, оставив неизменной только основную концепцию.
Так, мы добавили сущность Terraform Workspace, в атрибутах которой отображается вся необходимая информация о конфигурациях: имя, статус и ссылка на директорию в Git-репозитории.
GitLab является неотъемлемым компонентом платформы, поэтому мы решили хранить Terraform-конфигурации в нем. Это удобно, так как можно отследить всю историю изменений и не давать изменять конфигурацию без предварительного одобрения всех заинтересованных лиц. Для удобства конфигурация может быть разделена на несколько файлов.
На каждый запуск Terraform мы создавали сущность Terraform Workspace Execution, которая содержит всю информацию о запуске. У одного Terraform Workspace может быть N запусков.
Подробнее о параметрах запуска:
Status содержит информацию о статусе запуска: успешно выполнился, находится в процессе выполнения или завершился с ошибкой.
Action бывает двух типов: deploy и destroy, для развертывания и удаления инфраструктуры соответственно.
Commit hash содержит информацию о хэше коммита, чтобы можно было однозначно понять, с какой конфигурацией выполнялось развертывание, посмотрев изменения в GitLab.
Мы реализовали возможность развертывать инфраструктуру с помощью Terraform. При этом пользователю не надо устанавливать и настраивать сам инструмент, знать нюансы его работы, заботиться о хранении стейта, повторных выполнениях в случае ошибки и так далее. Все, что необходимо, — ввести ссылку на Git-директорию с заранее подготовленной Terraform-конфигурацией и запустить развертывание или удаление развернутой инфраструктуры одной кнопкой в платформе.
Итерация 2: Deployments (развертывания)
На следующем этапе развития платформы появилась задача доставки кода в развернутую инфраструктуру. Так как в качестве CI/CD в платформе мы используем GitLab, логичным решением было использовать раннеры для доставки кода.
Чтобы развернуть GitLab-раннер на виртуальной машине, необходимо выполнить следующие шаги:
создать раннер в GitLab, получить регистрационный токен;
развернуть виртуальную машину для раннера;
развернуть раннер на виртуальной машине и передать ему регистрационный код;
дождаться, когда развернется виртуальная машине, установится раннер, зарегистрируется в GitLab и перейдет в статус online.
Шаги по развертыванию виртуальной машины и установке на ней раннера может выполнить Terraform, но шаг с созданием раннера в GitLab лучше проконтролировать и выполнить в платформе, чтобы была возможность создавать разные ресурсы — в данном случае это раннер и Terraform Workspace, о котором мы говорили в первой итерации. Для возможности автоматически создать несколько связанных между собой ресурсов мы ввели сущность Deployment.
Фактически она нужна, чтобы предоставлять возможность разворачивать как стандартный Terraform, так и GitLab-раннер, который внутри себя также содержит шаг с выполнением Terraform.
Примечание: Сейчас у нас два варианта развертывания, но мы работаем над расширением этого перечня.
В Deployment мы передаем:
name — наименование развертывания;
type (terraform/runner) — на данный момент поддерживаем два типа: чистый terraform и GitLab-раннер на виртуальной машине;
status — содержит информацию о статусе развертывания: успешно выполнилось, находится в процессе выполнения или завершилось с ошибкой;
Terraform params (vars, vars_file, repository_directory, commit_hash) — все параметры аналогичны параметрам Workspace из предыдущей итерации, плюс добавили поддержку передачи Terraform-переменных;
runner params (tags, description) — для раннеров мы поддерживаем только передачу тегов и описания.
Для каждого развертывания (deployment) мы также внедрили планы (Deployment plans) по аналогии с Terraform plan. При создании плана мы делаем snapshot параметров, которые на данный момент содержатся в развертывании. При этом пользователь может дальше изменять параметры развертывания — это никак не повлияет на уже созданный план.
В Deployment plan мы передаем:
type (deploy/update/undeploy) — план может быть для инсталляции, удаления или обновления ресурсов определенных в развертывании;
status — аналогичен статусам развертывания;
Terraform params (vars, vars_file, repository_directory, commit_hash) — snapshot Terraform-параметров из развертывания;
runner params (tags, description) — snapshot runner-параметров из развертывания.
Каждый план развертывания состоит из зависимых друг от друга шагов. Например, так выглядят шаги для плана развертывания GitLab-раннера:
создаем раннер в GitLab;
выполняем команду Terraform apply;
ждем развертывания виртуальной машины для раннера;
дожидаемся, когда раннер поднимется на виртуальной машине и зарегистрируется в GitLab.
Deployment plan step хранит следующие параметры:
Type — тип шага, например create_gitlab_runner.
Predecessors — список шагов, от которых зависит текущий шаг, а значит, он должен дождаться выполнения шагов, от которых зависит, и только потом начать выполняться.
Status — у каждого шага есть свой статус, успешно он выполнился или нет. Глядя на ход выполнения плана, можно посмотреть, на каком шаге произошла ошибка, из-за которой план не выполнился.
Params — параметры, которые необходимы для выполнения конкретного шага. Например, прежде чем выполнять установку раннера на виртуальной машине, необходимо получить регистрационный код раннера, который получаем при создании раннера в GitLab на первом шаге. То есть шаг Terraform apply ждет выполнения шага Create GitLab runner. При этом между шагами могут передаваться необходимые параметры, например регистрационный код раннера.
Мы подробно рассмотрели сущности системы развертываний. Теперь давайте посмотрим, как ими пользоваться.
Платформа предоставляет API для создания и обновления развертываний, создания и запуск планов. Общая схема работы с развертываниями простая и очень похожа на работу, например, с Terraform:
Создать новую конфигурацию развертывания или обновить существующую.
Создать план на установку, удаление или обновление. Стоит отметить, что невозможно создать планы на удаление или обновление, если развертывание еще ни разу не запускалось.
Запустить ранее созданный план.
После выполнения необходимых действий все ресурсы, указанные в конфигурации, будут развернуты и готовы к использованию для разработки.
Пример создания интеграции, окружения и GitLab-раннера
Создаем новую интеграцию и проверяем подключение:
После успешной проверки подключения выбираем облачный проект и создаем интеграцию:
Создаем окружение на базе новой интеграции с VK Cloud. Сразу указываем Terraform-конфигурацию для установки виртуальной машины и выбираем автозапуск:
После нажатия на кнопку «Создать» вводим переменные Terraform и нажимаем кнопку «Запустить»:
После запуска мы можем посмотреть статус выполнения установки и убедиться, что виртуальная машина для окружения развернута:
Виртуальная машина появилась в облаке VK Cloud:
Проверяем ресурсы окружения:
Смотрим детали:
Помимо окружения, мы можем создать GitLab-раннер:
Вводим необходимые переменные Terraform и нажать «Запустить»:
В деталях запуска можно убедиться, что все шаги развертывания выполнены:
Можно посмотреть детали раннера и перейти на страницу раннера в GitLab:
Раннер успешно создан и перешел в статус «онлайн»:
Виртуальная машина для раннера также появилась в облаке:
Итоги и планы на будущее
Благодаря внедренным нами решениям и реализациям пользователи платформы получают возможность управлять вычислительными ресурсами и раннерами в любом из подключенных через Service connection облачных проектов для дальнейшего развертывания в них разрабатываемых приложений.
В платформе все ресурсы группируются в окружения. Так будет понятно, какие ресурсы использует каждый стенд в конкретном разрабатываемом проекте.
Это все стало возможным за счет доступных инструментов, в том числе Terraform as a Service, с помощью которого мы смогли разработать механизм развертывания необходимых для разработки инфраструктурных ресурсов.
Но на этом мы не останавливаемся: сервис активно развивается и в перспективе мы хотим внести улучшения:
показывать информацию о результатах и ошибках шагов;
отображать биллинг ресурсов окружения;
реализовать мониторинг ресурсов в платформе;
внедрить проверку квот перед развертыванием;
добавить шаблоны развертываний ресурсов;
добавить просмотр Terraform-плана;
добавить возможность разворачивать GitLab-раннеры не только на виртуальных машинах, но и в Kubernetes, а также подключать уже существующие.
Примечание: Подробнее об Platform Engineering, Internal Development Platform и Dev Platform вы можете прочитать в нашей серии статей здесь, здесь и здесь.