Автоматизация рабочих процессов была горячей темой примерно всегда. Как только появляется возможность решать какую-либо задачу более эффективным способом, сразу же возникает идея об оптимизации этого самого, казалось бы, уже совершенного способа. 

Серверная виртуализация, как и zVirt в частности, не стала исключением среди других рабочих процессов. Пользователи желают решать задачи быстрее, операторы хотят уменьшать количество шагов и ручных операций, время доставки виртуальной машины потребителю — основная функция серверной виртуализации — должно уменьшаться. И снижение влияния человеческого фактора — благодатная почва для оптимизации.


Меня зовут Михаил Фучко, я технический продакт-менеджер SDN и Terraform в команде zVirt. В этой серии статей я расскажу о пути, который проделала наша команда в процессе разработки собственного провайдера инфраструктуры для Terraform. Поговорим об успехах и трудностях, о том, всегда ли можно положиться на решение с открытым исходным кодом, и о том, как запущенные десять лет назад «бумеранги» возвращаются, но не тем, кто их запустил. 

Это первая часть цикла статей. В ней мы определимся с объектом автоматизации, обсудим ее основные концептуальные подходы и попытаемся сформировать глобальное видение результата. Для новичков в применении Ansible и Terraform данная статья может служить еще и небольшим введением в тематику. В последующих статьях сосредоточимся на инфраструктуре провайдера, поддержке ресурсов и их жизненных циклов и т.п. 

Объект автоматизации

Для начала определимся с тем, что именно мы хотим оптимизировать. В нашем случае — процесс эксплуатации с��стемы виртуализации. Определим его цель как «размещение полезных пользовательских нагрузок в формате виртуальных машин с организацией сопутствующей инфраструктуры для их функционирования».  

Действия в ходе этого процесса выполняет оператор системы виртуализации — по своему замыслу и плану. Заметим, что могут быть разные способы реализации замысла оператора, а следовательно и разные планы. 

На примере zVirt схематично рассмотрим, с помощью каких инструментов (в широком смысле этого слова) пользователь может реализовать свой план для достижения замысла:

Итак, в базе своей, «из коробки» zVirt управляется с помощью следующих механизмов:

  • Web UI, графический пользовательский интерфейс. Построен на основе RPC-эндпоинтов по технологии GWT; 

  • REST API, традиционный (уже) программный интерфейс, на основе HTTP-запросов и JSON \ XML объектов. 

Внимательный читатель заподозрит неладное. Почему графический интерфейс использует отдельную ветку вызовов, а не опирается на REST API? Здесь и пришло время рассмотреть первый увесистый «бумеранг», отправленный разработчиками в будущее. При внедрении изменений нельзя останавливаться на половине, фарш нужно проворачивать до конца. 

Суть проблемы — первые появления oVirt как гипервизора датируются 2008 годом, когда до полного доминирования концепции REST было еще далеко и она зародилась в oVirt как альтернативный доступ к внутренним функциям, тогда как UI использовал более оптимальные (с точки зрения разработчика на тот момент) и глубоко интегрированные с Java инструменты разработки интерфейса на основе GWT-RPC. Таким образом, с момента появления REST API в 2012 году в oVirt эти две ветки продолжали существовать параллельно, что критическим образом сказалось на качестве REST API. Если инструментом не пользоваться, по нему не будет накапливаться опыт эксплуатации, непонятно, как его чинить и куда улучшать.

Плохо скрываемая боль от необходимости активной борьбы с унаследованным API oVirt будет пронизывать все статьи этого цикла, можете мне поверить. Немного спойлеров, для затравки, пока без примеров:

  • Иногда что-то нельзя сделать через REST API, но можно через UI. Просто нет такого поля, его нельзя задать;

  • Иногда через REST API можно сделать что-то, что нельзя посмотреть в UI. Аналогично — ��росто нет таких полей;

  • Иногда сделанное через API вызывает «пятисотые» ошибки при чтении результата через UI;

  • Иногда пустой вызов REST API вызывает весьма серьезные изменения в нетривиальных местах. 

Разработчики оригинального oVirt не стали доводить процесс до конца, так что мы в команде zVirt выполняем эту задачу сами. Сетевая оснастка, начиная с версии 4.5, уже полностью использует REST API  и реализует модернизированный подход к менеджменту сетей. В процессе мы чиним баги оригинального API и делаем альтернативные реализации там, где это требуется. Если вам известно другое необычное поведение oVirt API, дайте знать. 

«Сценарий» и «манифест»

Современная ИТ-автоматизация опирается на экосистему общепризнанных инструментов, у каждого из которых своя логика работы. Вендоры ПО добавляют поддержку продуктов через разработку плагинов. Ответственность за их качество лежит на разработчике (впрочем, иногда и на сообществе). 

Средства автоматизации — это инструменты,  с помощью которых оператор описывает сценарии, а система их выполняет. Они упаковывают рутинные операции в блоки и инструкции высокого уровня, которые оператор (уже как автор плана автоматизации) комбинирует в зависимости от ситуации. Инструкции обычно представлены в согласованной нотации, скриптовом языке высокого уровня, которые система автоматизации понимает и готова исполнять. 

В автоматизации сложилось два принципиальных подхода к решению задач:

  • «Сценарий» — описание действий, необходимых для достижения результата. Оператор фиксирует желаемый результат, замысел, и описывает план действий на языке системы автоматизации, после чего запускает его на исполнение;

  • «Манифест» — описание результата, которого необходимо достигнуть. Оператор описывает результат на языке системы автоматизации, запускает его в работу, и система самостоятельно формирует план для достижения данного результата. 

Первый подход дает больше контроля в моменте, но заставляет все продумывать самостоятельно. Второй позволяет сразу описывать желаемое целевое состояние, но заставляет мириться с выработкой плана автоматическими алгоритмами.

Ярким представителем «сценарного» подхода является проект Ansible. Это программный комплекс, который позволяет реализовывать заложенный сценарий через обращения к у��равляемым хостам по SSH и исполнения команд на месте. В основе лежит концепция плейбуков — наборов четких процедур («задач», «tasks»), из которых пользователь, как из кубиков, собирает итоговое решение. Разработчики ПО несут ответственность за эти «кубики».

Например, процедура создания виртуальной машины — она на вход принимает нужные параметры, а уже внутри Python-реализация делает все необходимые валидации, вызовы API и так далее. Задачи строятся вокруг модулей, наборы задач называются плейбуками, «пьесами». 

В основном Ansible решает задачи управления программным обеспечением внутри готовой инфраструктуры (хотя тот же oVirt имеет Ansible-модули, пассатижами тоже можно забивать гвозди). Ansible проходит по готовому набору виртуальных машин («инвентарь») и исполняет высокоуровневые команды — установку ПО, создание конфигов, запуск контейнеров и т.п.

Пример сценария Ansible. Последовательно описаны шаги аутентификации в API zVirt, создание виртуальной машины и завершение сессии.
Пример сценария Ansible. Последовательно описаны шаги аутентификации в API zVirt, создание виртуальной машины и завершение сессии.

Ну а доминирующим представителем подхода «Манифест» является программный комплекс Terraform. Он как раз реализует концепцию «Инфраструктура как код». Здесь фокус уже на создание самих объектов инфраструктуры — виртуальных машин, дисков, сетей — а также их взаимоинтеграцию и регистрацию. 

Пользователь описывает, что он желает видеть: «Три виртуальных машины, пять дисков, все это в одну сеть, на нее — правила межсетевого экрана, разрешить SSH на всех, RDP — только до этого сервера…» — а система уже формирует набор шагов, реализуя описанную разработчиком логику взаимосвязей:

  • Виртуальные машины, согласно манифесту, должны иметь подключенные диски. Видимо, сначала создадим диски;

  • Виртуальные машины при старте должны быть подключены к сети — значит, сначала создадим сеть;

  • Правила межсетевого экрана у нас применяются к портам виртуальных сетевых карт — ну, пора создавать виртуальные машины…

Таким образом Terraform, запуская разработанные поставщиком инфраструктурного ПО механизмы, строит граф зависимостей и принимает решение, что нужно создать раньше, что позже, а что можно создавать параллельно. Пользователь может немного влиять на его поведение, но в общем случае принимает его как данность. 

Пример манифеста Terraform для zVirt. Описана конфигурация виртуальной машины, логической сети и подсети. Для виртуальной машины предусмотрен загрузочный диск в 25 гигабайт, в другом файле определен кластер для запуска
Пример манифеста Terraform для zVirt. Описана конфигурация виртуальной машины, логической сети и подсети. Для виртуальной машины предусмотрен загрузочный диск в 25 гигабайт, в другом файле определен кластер для запуска

Инфраструктура как код 

Желание оптимизировать рутину и сэкономить пару минут вылилось в формирование полноценного подхода к управлению инфраструктурой — «Инфраструктуру как код». Действительно, если отдельные операции мы можем выполнять в формате, близком к кодовому (скрипты по сути те же программы), то почему бы не автоматизировать все, что только можно? 

Что если вся инфраструктура управляется с помощью кода? А для создания виртуальной машины достаточно, чтобы в соответствующем файле было ее описание и данный файл прочел некий «компилятор»? 

Разумеется, это светлый идеал, к которому стоит стремиться, но которого вряд ли можно достичь (вера в условный terraform и качество его логики принятия решений должна быть запредельной, а мы еще поговорим о необходимости «доверять, но проверять» в следующих статьях цикла). 

Тем не менее концепция имеет право на жизнь: она применяется в очень гибких и динамичных инфраструктурах. Ключевое преимущество в том, что мы используем  все лучшее из мира разработки: многолетние практики и целый класс вспомогательного ПО. Что бы мы могли от такого подхода получить:

  • Код можно выполнить сразу и массово — вместо ручной работы операторов;

  • Код выполняется с высокой степенью повторения и с минимизацией человеческого фактора — машины реже ошибаются;

  • Если инфраструктура — это код, то его можно положить в репозиторий! А значит версионирование, ветки, MRы, коммиты, полная история изменений, переключение на состояние инфраструктуры в нужный момент — все то, что программисты делают рутинно и постоянно, — теперь можно получить в свое пользование;

  • Самодокументирование: код уже документ, коммит кто-то выполнил, кто-то его принял — все в условном gitlab будет отражено, там же и вся инфраструктура согласований и проверок;

  • Метапрограммирование: программу могут писать другие программы. Код инфраструктуры может генерироваться самыми разнообразными средствами без необходимости вводить поддержку API вручную в каждое из них. 

И все прочее, что можно придумать. Среди наших заказчиков есть опытные команды, которые уже используют подход на базе Terraform, поэтому от них и прозвучал справедливый вопрос: «А где?».

Резюме

Стремление вендоров добавить поддержку Terraform понятно и логично. Популярность концепции IaC растет, требования к скорости развертывания и доставки изменений растут, инфраструктура становится все более динамичной. Возможность продукта работать в такой парадигме может стать решающим преимуществом. Для zVirt это важно еще и в связи с необходимостью импортозамещать решения на базе VMWare — у них с работой в IaC все прекрасно. И в один прекрасный момент появился заказчик, которому «или так, или никак». Есть компоненты инфраструктуры, живущие по принципам IaC, и замещение виртуализации не должно привести к откату в развитии. 

В следующей статье цикла мы чуть детальнее рассмотрим, что же такое Terraform и куда конкретно нам надо добавить свой код, чтобы обеспечить его полноценную поддержку. Если у вас появились вопросы — пишите в комментариях.