Привет, Хабр! Меня зовут Вячеслав Савельев, я отвечаю за разработку ключевых сервисов Учи.ру. Сегодня расскажу, как в процессе постепенного внедрения микросервисов в компании (тут, тут и тут можно прочитать об этом подробнее) мы столкнулись с проблемой конфигурации стейджовых окружений. И вот как мы с ней справились.
Шаман и шотилка
Когда у нас появились микросервисы мы столкнулись с рядом проблем в их использовании и конфигурации. Одна из них — отсутствие тестового окружения, которое было бы полностью настроено. Тестовое окружение в идеале должно повторять продакшн, у нас же они довольно сильно различались.
Проведем короткий исторический экскурс в нашу инфраструктуру, чтобы понять, почему так сложилось. Все приложения крутятся в контейнерах и оркестрируются через nomad. Так как в компании нет отдельных девопсов, конфигурация приложений для прода лежит на разработчиках.
Чтобы всем разработчикам не приходилось лезть в дебри конфигурации nomad и больше программировать на Ruby, а не на yml, у нас существует самописный UI под названием «шаман». Он абстрагирует управление оркестратором и конфигурацию приложения для обычных кодеров. В этом UI можно указать какие контейнеры и с какими аргументами запускать, указывать env переменные, выбирать в скольких инстансах разворачивать и так далее.
Сделать конфигурацию одного экземпляра приложения в проде руками через интерфейс несложно. Но так как стейджей много, и они должны быть легко повторяемы, это нужно автоматизировать. Следовательно, должны быть какие-то шаблоны конфигураций приложений, которые можно переиспользовать.
Для этого у нас существует так называемая шотилка — репозиторий с шаблонами конфигураций (конечно же в yml, от него скрыться) плюс веб-приложение, позволяющее выбрать шаблон (шот), через простейший интерфейс. Принцип следующий — нужно выбрать, куда им «выстрелить» и нажать на «спусковой крючок» (кнопку деплоя). «Шотилка» отправит POST-запрос в «шаман» со всей конфигурацией, и он начнет поднимать окружение.
Сама «шотилка» была написана несколько лет назад и особо никем не поддерживалась, туда просто коммитили новые шаблоны. Теперь перейдем к описанию проблемы.
Ресурсы, которых никогда не бывает много
Шаблон в «шотилке» содержал в себе полную конфигурацию окружения со всеми сервисами. Это хорошо работало, когда был только монолит, каждая команда создавала себе шаблон с сабсетом тех настроек, которые необходимы для работы, и все были довольны. Но с появлением новых сервисов сложность системы росла, для поднятия базового окружения одного монолита уже было недостаточно.
Сложилась следующая ситуация — появился шаблон, в котором существует базовая конфигурация окружения: HTTP Proxy с роутингом, монолит + сервис аутентификации + сервис профилей пользователей. Далее этот шаблон копировался каждой командой, в прокси дописывались новые роуты, конфигурация базовых приложений менялась под нужды команды, туда добавлялись их собственные приложения. Иногда под каждое отдельное приложение команды шаблон копировался несколько раз. Таких шаблонов через какое-то время стало несколько десятков.
Во-первых, это просто избыточно и совсем не DRY. Во-вторых, выявился еще ряд проблем. Например:
проблемы со связью сервисов;
нигде не было единого представления системы целиком;
во всех шаблонах были по-разному проставлены лимиты по памяти;
во многих шаблонах лимиты по памяти проставлены избыточно;
много памяти было выделено под приложения, при этом она не использовалась и пропадала впустую.
Все эти проблемы замедляли наш процесс доставки или заставляли выделять на тестовое окружение слишком много лишних ресурсов: как временных, так и денежных.
Таким образом, не замечать проблему в какой-то момент стало невозможно. Настало время ее решать.
На пути к идеалу
Первый шаг был очевидным: нужно было собрать все шаблоны в кучу и исключить их повторение. У каждого сервиса должен быть только один экземпляр конфигурации с владельцем продукта, отвечающим за поддержку. Конфигурация общих сервисов должна накапливаться в одном шаблоне, все они должны быть настроены таким образом, чтобы без дополнительной конфигурации могли работать друг с другом в рамках экземпляра окружения.
Если на каждый отдельный сервис есть свой шаблон, то для разворачивания всего окружения нужно иметь возможность собирать его из нескольких шаблонов. Для этого необходимо было дописать «шотилку», добавив туда функциональность по комбинированию шаблонов. Эту задачу на себя взяла моя команда.
Чтобы ничего не сломать в имеющейся реализации, мы просто скопировали весь код, и разнесли его на два неймспейса внутри приложения: условно «старое» и «новое». Новое гордо окрестили «шотилкой 2.0», обновили интерфейс, добавили возможность выбора множественных шаблонов и на бэке сделали функциональность мерджа этих конфигов в один перед отправкой в «шаман».
Сейчас процесс создания нового экземпляра тестового окружения следующий:
Выбираете HTTP Proxy под ваше окружение (Учи.ру работает не только в России) и прокси содержит роуты под все маршруты всех приложений.
Выбираете те приложения, которые хотите задеплоить.
Еще мы добавили возможность обновить уже созданное раннее окружение, додеплоив туда ранее не использовавшиеся приложения. MVP было сделано, дальше нужно было решить проблему переноса старых шаблонов и внедрения среди всех команд.
Для этого я лично обошел лидов и главных разрабов всех команд, рассказал им о преимуществах, показал новую документацию, объяснил, как всем пользоваться. После попросил их допилить свои шаблоны для нашей «шотилки 2.0».
Также я завел отдельный канал в Slack, куда можно было задавать вопросы. Там же оповещал о новых доработках.
Постепенно люди стали переносить свои шаблоны, в этом процессе я активно помогал с их настройкой и лично проверял, что все настроено правильно, деплоится и работает без ошибок.
По графикам в интерфейсе Grafana для уже развернутых старых окружений проверял потребляемые ресурсы, уменьшал их до состояния, чтобы приложения не расходовали их бессмысленно. Также следил, чтобы все сразу прописывали уже правильные значения в новых шаблонах. Этим смогли заметно сократить количество затраченных ресурсов на стейджи.
Шаблоны приложений были закреплены за командами через CODEOWNERS-файл в гитхабе, чтобы при изменении конфига ответственная команда об этом знала и дала апрув.
Для упрощения жизни себе и разрабам добавил скрипт валидации шаблонов, проверяющий на самые частые ошибки в конфигурации, и добавил его в GitHub Action.
В течение пары месяцев большинство команд полностью добавили свои приложения на новую версию, использование уже вошло в привычку. Теперь все новые приложения сразу заводятся там, а существующие конфиги активно дополняются.
Благодаря этому постепенно тестовое окружение все больше и больше становится похожим на то, что у нас в продакшене. Различия пока еще довольно сильные, но мы пытаемся свести их к минимуму.
В случае появления новых команд и микросервисов у нас уже существует готовое решение для них, с которым они могут работать. Есть документация, в которой объясняется, как это сделать, есть канал, в который можно задавать вопросы, есть примеры и есть команда, отвечающая за все это и следящая, чтобы все продолжало работать.
А вы сталкивались с подобными проблемами? Как решали их?