Хабрахабр

Разработка новой ветки продукта: как избавиться от непрактичного и сохранить полезное

Меня зовут Дмитрий, я разработчик в ISPsystem. Привет, Хабр! Сегодня я расскажу, как мы решали, что взять из старого продукта, а от чего лучше отказаться. Недавно мы выпустили в бета-тестирование новую версию панели управления виртуальными машинами. Пройдусь по самым важным для нас вопросам: библиотека для работы с libvirt, поддержка различных ОС при установке продукта, переход от монолита к микросервисам, развёртывание виртуальных машин.

Это система управления, развёртывания и мониторинга виртуальных машин на основе виртуализации KVM и OVZ. В статье речь идёт о VMmanager. С тех пор интерфейс сильно устарел, а централизованная архитектура мешала развивать продукт. Пятое поколение вышло в 2012 году. Пришло время делать новую версию.

История первая. Используем труд домовых эльфов

Работа с libvirt: рассматриваем варианты, выбираем библиотеки

Как инструмент управления KVM-виртуализацией в нашем продукте используется libvirt. В 2012 году для работы с ним была выбрана библиотека, написанная на C, так было удобнее для той команды разработки. Как результат — большой объем кода, написанный на C++, вызывающий С-библиотеку, которая реализует непосредственную работу с libvirt.

И вот мы на пороге нового проекта оглядываемся назад и осматриваем наш продукт, взвешиваем, стоит ли брать то или иное решение/технологию; что зарекомендовало себя, а что нужно запомнить и никогда не повторять.

Запасаемся терпением, берём стикеры и пишем три вида бумажек:
Садимся и делаем ретроспективу многолетней работы над предыдущей версией продукта.

  1. Что удалось в продукте? Что хвалили пользователи? На что ни разу не слышали жалоб? Что нравилось самим?
  2. Что не удалось? С чем постоянно были проблемы? Что мешало работе, и почему начали новую ветку?
  3. Что можно изменить? Что просят пользователи? Что хотят изменить члены команды?

В группе людей, рьяно портящих бумагу, должны быть как те, чьё тесное общение с продуктом исчисляется столетиями, так и те, у кого может быть свежий взгляд на продукт. Не забываем Feature Request и продукт-менеджера. Готовые стикеры клеим на доску, они нам обязательно помогут.

Вернёмся к истории. Осматриваем кусок кода, где C++ 98 стандарта мирно соседствует с вызовами С-библиотеки. Вспоминаем, что на дворе 2018 год и решаем оставить его в покое. Но как повторить функциональность работы с виртуальными машинами (ВМ), сделав код более компактным и удобным для работы?

Как интересный вариант стоит отметить библиотеку на Go от DigitalOcean, она использует протокол RPC для общения с libvirt напрямую, но у неё есть свои недостатки. Изучаем вопрос, понимаем, что какое бы решение и на каком языке мы ни выбрали, это будет обёртка над C-библиотекой. Мы остановились на Python-библиотеке.

Стоит пояснить эти красивые слова.
В результате получили скорость написания кода, простоту использования и чтения.

  • Скорость. Теперь мы можем быстро прототипировать определённую часть работы с доменом прямо из консоли на отладочном сервере, без пересборки основного приложения.
  • Простота. Вместо вызова множества C++ методов в неком хендлере, мы имеем вызов Python-скрипта с передачей параметров.
  • Отладка также максимально быстра и безболезненна. На мой взгляд, в перспективе это может нести интересный пользовательский опыт. Представьте, системный администратор, недовольный, что его виртуальные машины ждут shutdown перед destroy, идёт и переопределяет скрипт для метода host_stop. Может мне за вас еще и панель писать?

Как итог, мы получили простой и удобный инструмент для работы с виртуальными машинами на уровне сервера.

История вторая. Хорошо упакованный продукт в дополнительных ласках не нуждается

Распространение продукта: отказываемся от множества пакетов и переходим на Docker


VMmanager 5 распространяется как набор linux-пакетов. Поддерживаются CentOS 6/7 и до недавнего времени Debian 7. О чём это говорит? Это значит, больше сборочных серверов для CI/CD, больше тестирования, больше внимания к коду. Надо помнить, что когда в официальном репозитории CentOS 7 qemu версии 1.5.3, в CentOS 6 — это 0.12.1. При этом пользователь может использовать репозитории, в которых версия этого пакета значительно выше. Это значит, надо поддерживать различные версии api при работе с ВМ, в частности, при миграции. Надо помнить про разницу инициализаторов (init, systemd), учитывать разницу в названиях пакетов и утилит. Те утилиты, которые работают в CentOS, не сработают в Debian либо их версии в официальных репозиториях сильно разнятся. На каждый push нужно собрать пакеты для всех версий, и протестировать их тоже желательно не забыть.

Чтобы не поддерживать различную логику, отказываемся от нескольких систем и оставляем только CentOS 7. Всё это в новом продукте нас не устраивает. Не совсем. Проблема решена?

Хочется раз — и всё, по щелчку уничтожить каждого второго развернуть всё окружение и сам продукт. Мы также не хотим перед установкой проверять версию операционной системы, доступны ли необходимые утилиты, какие правила установлены в SELinux, не хотим переконфигурировать файервол и списки репозиториев. Сказано — сделано, проект завёрнут в докер-контейнер.

Теперь достаточно сделать:

# docker pull vmmanager
# docker run -d vmmanager:latest

Панель запущена и готова к работе.

О том, с чем мы столкнулись, выбрав Docker, и как это решали, можно написать отдельную статью. Конечно, я утрирую, пользователь должен установить себе Docker, да и контейнер у нас не один, и в настоящее время VMmanager запускается в swarm-режиме как SaaS-сервис.

Важен сам факт, насколько можно упростить разработку, а главное — развёртывание вашего продукта, install.sh которого некогда занимал 2097 строк.

Как итог:

  1. Гомогенная среда установки продукта упрощает программный код, уменьшает затраты на сборку и тестирование.
  2. Распространение приложения как докер-контейнера делает развёртывание простым и предсказуемым.

История третья. Первые отношения с микросервисами

Архитектура: отказываемся от монолита в пользу микросервисов, или нет


Пятая версия продукта представляет собой большую монолитную систему с устаревшим стандартом С++. Как следствие — проблемное внедрение новых технологий и сложность рефакторинга legacy-кода, плохое горизонтальное масштабирование. В новой ветке решили использовать микросервисный подход как один из способов избежать подобных проблем.

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

Положительные стороны

Небольшой сервис даёт много возможностей
Помимо удобства написания, тестирования и отладки, микросервисы привнесли в проект новый язык программирования. Когда ваш проект представляет собой монолит, сложно представить, что в один прекрасный день вы попробуете переписать его часть на другом интересном вам языке. В микросервисной архитектуре — пожалуйста. Помимо языка программирования, вы также можете попробовать новые технологии, с той лишь оговоркой, что всё это будет обоснованным для бизнеса. Мы, например, написали часть микросервисов на Golang, сэкономив при этом порядочное количество времени.

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

При этом это всё-таки положительная сторона. Независимая деградация
Независимую деградацию я бы отнёс и к положительным и к отрицательным сторонам микросервисов, ведь кому нужно ваше приложение, если лежит, к примеру, сервис авторизации? Отдельный сервис сбора статистики может собирать её, не затрагивая остальные сервисы, при этом его ещё можно масштабировать, добавив нового железа или увеличив количество сборщиков той самой статистики. Раньше сбор статистики с нескольких сотен виртуальных машин заставлял хорошенько напрягаться наш монолит, в момент пиковой нагрузки ожидание выполнения запроса пользователя возрастало в разы. С монолитом, где одна база, такое невозможно. И можем даже выделить отдельный сервер под Graphite, куда этот сервис статистику и записывает.

Отрицательные стороны

Контекст запроса
Весь мой debugging в монолите сводился к двум запросам в консоли:

# tail -n 460 var/vmmgr.log | grep ERR
# tail -n 460 var/vmmgr.log | grep thread_id_with_err

Готово! Я могу отследить весь запрос, от его поступления в систему до возникновения ошибки.

Для этого мы реализовали request info, которое содержит идентификатор запроса и информацию о пользователе или сервисе, который его произвёл. Но как же быть теперь, когда запрос путешествует из микросервиса в микросервис, сопровождаясь дополнительными вызовами соседних сервисов и записями в различные БД? Можно также посмотреть в сторону Elasticsearch, этот вопрос открыт и будет решён в скором времени. Так становится проще отследить всю цепочку событий, но приходит желание написать сервис агрегации логов, у нас ведь, в конце концов, микросервисная архитектура.

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

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

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

Отлично, делаем микросервис сбора статистики. Что касается остальных микросервисов, невозможность зарегистрироваться в сервисе статистики никак не влияет на работу виртуальной машины, и это действие всегда можно повторить. А вот сервис define domain (создание виртуальной машины посредством libvirt) свет так и не увидит, так как кому нужна болванка машины без её фактического существования.

История четвертая. Свежее — враг хорошего

Развёртывание ВМ: установка из образов взамен установки по сети

В пятой версии продукта развёртывание виртуальной машины занимает довольно продолжительное время по настоящим меркам. Причиной этому служит установка операционной системы по сети.

Создаём kickstart-файл.
2. Для Centos, Fedora, RedHat — это kickstart-метод:
1. Запускаем kickstart-установку. Указываем ссылку на файл ответов в параметрах ядра linux inst.ks=<ссылка на файл kickstart>.
3.

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

В нём мы тоже настроили установку по сети. Для Debian и Ubuntu — метод preseed:
Он схож с предыдущим, этот метод также построен вокруг конфигурационного файла и его содержимого.

Аналогична и установка для FreeBSD, только вместо kickstart-файла — shell-скрипт собственного производства.

Положительные стороны подхода

Данный вариант установки позволяет использовать один шаблон в двух наших продуктах: VMmanager и DCImanager (управление выделенными серверами).

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

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

Отрицательные стороны

Как показала практика, гибкость установки оказалась не нужна пользователям VMmanager: в сравнении с выделенными серверами, специфические настройки kickstart-файла для виртуальных машин мало кого волновали. А вот ожидание установки ОС было действительно непозволительной роскошью. Обратная сторона актуальности операционных систем состоит в том, что часть инсталлятора находится в сети, а часть — локально в initrd. И их версии должны совпадать.

Можно создать пул установленных машин и завести собственный репозиторий для операционных систем, но это влечёт дополнительные расходы. Это решаемые проблемы.

Мы выбрали файлы образов операционных систем. Как решить эти проблемы, не создавая репозиториев и пулов? Копирование образа ОС в диск виртуальной машины.
2. Теперь процесс установки выглядит так:
1. Базовая настройка (установка пароля, часового пояса и т.д.). Увеличение основного раздела образа на размер свободного места после копирования.
3.

Образы ОС мы использовали в VDSmanager-Linux — прародителе VMmanager. Всё новое — это хорошо забытое старое.

Практика показала, что большинство пользователей не интересуют специфичные настройки сети и разбивки дисков на виртуальных машинах.
А актуальность данных? А как же гибкость установки? Таким образом, виртуальная машина будет уже создана и запущена, а зайдя на нее, вы обнаружите запущенным условный yum update. Её можно достичь наличием образов с актуальными версиями ОС в репозитории, а минорные обновления можно установить в скрипте первоначальной настройки.

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

К примеру, смена пароля на linux-машине превратилась из 40 строк кода, состоящих из mount, chroot и usermod, в одну строку: Конфигурацию и изменение разделов мы реализовали с помощью утилит из набора libguestfs.

command = "/usr/bin/virt-customize --root-password password: --domain '{domain_name}'".format(password=args.password, domain_name=args.domain_name)

В результате мы сделали получение готовой виртуальной машины максимально быстрым. Стоит сделать ремарку, что с настройкой сети и установкой внутренних скриптов время развёртывания немного увеличилось. Мы решили этот вопрос отображением шагов установки на фронтенде, заполнив таким образом паузу, образовавшуюся между созданием и полной готовностью машины.

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

Что удалось сделать

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

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

Для этого перейдите на my.saasvm.com, авторизуйтесь и подключите выделенный сервер (CentOS 7 x64, доступ в интернет, публичный IP-адрес). Приглашаем сообщество Хабра посмотреть бета-версию VMmanager 6 и оставить свои отзывы.

Если у вас нет сервера, напишите нам на help@ispsystem.com или в чат на сайте, мы предоставим оборудование для тестирования от нашего партнёра, компании Selectel.

Подробнее читайте в новости на сайте ISPsystem.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть