Как PaaS решил проблемы стандартизации разработки сервиса одной утилитой
- суббота, 14 октября 2023 г. в 00:00:17
Привет 👋 На связи команда PaaS СберМаркета. Меня зовут Роман, и уже больше 2-х лет моя группа занимается разработкой инструментов для разработчиков, в том числе утилитой sbm-cli, о которой хочу рассказать сегодня.
Вероятно вы каждый день пользуетесь консольными утилитами, такими как git, homebrew, ssh, grep, find, etc. Мы сделали command line interface приложение, запуск которого на локальной машине разработчика может превышать количество запусков команды git (спойлер: статистика в конце статьи).
О том как так получилось, почему этот инструмент так важен для разработчика и что он умеет, а что нет, расскажем в этой статье.
Обо всем по порядку:
Это третья статья из цикла о разработке IT-платформы. В предыдущих сериях:
Классическая проблема, с которой вы можете столкнуться во время разработки — это использование разных версий инструментов для обслуживания ваших сервисов.
В примере ниже это cli-приложение oapi-codegen — утилита для генерации Go-кода на основе openapi спецификации. Каждый разработчик ставит себе @latest и скоро версии oapi-codegen расходятся даже у членов одной команды.
Вероятно, вы сталкивались с тем, что в соседних проектах для <чего-либо> (http client'а, авторизации, генерации кода, ORM и т.д.) используются разные библиотеки. На первый взгляд это не является проблемой, но со временем точно ей становится — когда приходится тратить много время на получение экспертизы N технических компонентов, реализующих смежные технологии.
Еще одна типичная боль для разработчика — выбор инструментов для локального запуска сервиса и его зависимостей:
кто-то запускает приложение и зависимости нативно (go run, python *.py runserver, systemctl start postgresql, etc);
кому-то ближе история с docker-compose;
есть любители minikube.
Список подобных разногласий может быть достаточно объемным. Чтобы минимизировать количество таких болей мы и сделали sbm-cli.
Давайте представим крутую команду инженеров (скорее всего вы в такой работаете), которая разрабатывает и обслуживает N микросервисов.
Перед вами встаёт задача написать новый сервис, например, промокодов.
Он будет ходить в сервис заказов.
Забирать некоторую информацию.
Агрегировать ее и отправлять в кафку.
Спецификации API в сервисе заказов не оказалось или она просто устарела. Поэтому разработчик курит изучает код, чтобы получить возможные варианты входных и выходных параметров API. В итоге, для решения задачи он потратил на 2 дня больше, чем планировал.
Может показаться, что это не так много. Но представьте, что подобная проблема встречается в каждом сервисе, и каждая новая интеграция требует еще больше времени. Ситуация усугубляется, когда с подобной проблемой сталкивается не только один инженер, но и вся команда.
При создании sbm-cli у нас была одна основная цель: ускорить процесс доставки ценности. И мы руководствовались простым принципом: если что-то можно автоматизировать, то это нужно сделать.
На сегодняшний день sbm-cli содержит команды из шести доменных областей. Далее подробнее поговорим о каждой.
системные команды
Управление шаблоном сервиса
sbm-cli service create
sbm-cli service upgrade
Локальная среда разработки (Playground)
sbm-cli service up
sbm-cli service down
sbm-cli service debug
sbm-cli service reset
sbm-cli service purge
sbm-cli service status
sbm-cli service env
Работа с API
sbm-cli dependency add
sbm-cli dependency upgrade
sbm-cli contract list
sbm-cli codegen
Работа с БД
sbm-cli database create
sbm-cli migration create
sbm-cli migration apply
sbm-cli migration rollback
Валидация
sbm-cli code lint
sbm-cli contract verify
sbm-cli dependency check
sbm-cli manifest check
sbm-cli inframanifest check
sbm-cli setup system-check
Системные команды
sbm-cli setup self-upgrade
sbm-cli setup autoupgrade
sbm-cli setup token-set
sbm-cli version
Для каждой команды соблюдаются следующие правила интерфейса:
Help: Понятная помощь на старте с примером запуска команды.
Next steps: Рекомендации по выполнению дальнейших действий после успешного завершения команды.
What to do: Ответ на вопрос «Что надо сделать, что бы команда успешно прошла?»
Exit codes: 0 — успех, 1 — ошибка, 3 — предупреждение.
Экосистема PaaS построена вокруг главной сущности — сервиса. Для обеспечения корректной работы платформы мы приняли ряд конвенций. Поэтому наше типичное приложение имеет следующую структуру каталогов в сервисе, вне зависимости от выбранного engine (языка или фреймворка):
Engine — основная технология на которой построен сервис. В СберМаркете это Golang, Rails, Python и NodeJS.
Для обеспечения такого соглашения мы сделали свой механизм создания сервиса. Именно с него началась разработка sbm-cli. Мы вдохновились лучшими практиками шаблонизации сервисов:
project-layout для Golang;
rails application template для Ruby;
aiohttp-demo для Python.
И объединили их с конвенциями принятыми в платформе.
Пример создания сервиса:
sbm-cli service create https://git.sbermarket.tech/paas/test-python-service --engine=python
В статье Как подступиться к созданию PaaS мой коллега подчеркивал важность стандартного набора библиотек для разработки сервисов. Поэтому для каждого engine была разработана своя God-библиотека <engine>-libs (go-libs, ruby-libs, etc), которая предоставляет API для использования библиотеки следующего уровня.
Например, вы хотите использовать ruby http client faraday. ruby-libs предоставляет инстанс faraday с базовой конфигурацией, миддлварами, единым форматом логов и метрик, которые общеприняты в платформе.
С течением времени наши базовые шаблоны менялись, и мы решили добавить функцию обновления в sbm-cli с командой sbm-cli service upgrade, чтобы упростить процесс перехода на новые версии библиотек.
Docker-compose является достаточно эффективным инструментом для локального запуска приложения и его зависимостей. Но писать новый docker-compose.yaml каждый раз для нового сервиса — весьма утомительно. Наша команда поставила себе цель, сделать так, чтобы для локального старта любого сервиса разработчик выполнил как можно меньше действий. Так появилась команда sbm-cli service up.
Playground — это docker-compose-based компонент sbm-cli, который управляет жизненным циклом сервиса на локальной машине разработчика.
sbm-cli service up разворачивает приложение и все его инфраструктурные зависимости. Список зависимостей определяется в configs/values.yaml и используется как при деплое приложения, так и при локальном развертывании.
сonfigs/values.yaml — манифест инфраструктуры, в котором декларируется поведение сервиса и его зависимостей в staging, production и playground среде.
При необходимости, разработчик может указать точную версию образа, который необходим для развертывания зависимости. В противном случае будет выбрана версия по умолчанию.
Playground предоставляет возможность запустить docker-контейнеры только с инфраструктурными зависимостями. При этом запуск самого приложения может оставаться на локальной машине.
Остальные команды playground:
sbm-cli service debug — запускает приложение в режиме debug (например с использованием delve для golang).
sbm-cli service down — останавливает приложение.
sbm-cli service status — отображает состояние приложения.
sbm-cli service reset — down & up.
sbm-cli service purge — полный сброс (останавливает приложение и удаляет все образы, контейнеры, вольюмы, сети).
sbm-cli service env — вызов команды в контексте playground (например sbm-cli service env -- go test -v ./…
запустит тесты в окружении env переменных для подключения к ресурсам, развернутым в playground).
Наша tech-команда выбирает API-first подход при разработке. Подробнее можно прочитать в статье: Трудности перевода. Как научить микросервисы общаться и не ссориться.
Этот метод предоставляет ряд ключевых преимуществ:
улучшение качества проектирования приложения;
всегда актуальные контракты для разработки;
разработчики могут одновременно работать над клиентской и серверной частями приложения.
Как это работает на практике? Разработчик сервиса-продьюсера формирует контракт в директории api. Затем он может применить инструмент кодогенерации sbm-cli codegen –servers для автоматической генерации серверного кода на основе этого контракта.
Мы используем openapi и proto спецификации. Кодогенерация доступна для каждого вида контракта.
Разработчик сервиса-консьюмера использует команду sbm-cli dependency add перед реализацией интеграции. Она выполняет несколько функций:
Декларирует интеграцию в манифесте приложения app.toml.
Скачивает контракты сервиса в директорию deps/services/<service-name>/<contract-name>.
Генерирует клиентский код (как команда sbm-cli codegen –clients).
В манифесте инфраструктуры values.yaml прописывает сетевой доступ для межсервисного взаимодействия в kubernetes.
Одна команда закрывает большую часть вопросов и разработчик может сфокусироваться на написании кода.
Что делать если в контракте добавилось новое поле и необходимо его поддержать со стороны консьюмера? Для этого есть команда sbm-cli dependency upgrade, которая актуализирует контракт и клиентский код.
Для просмотра всех контрактов сервиса используется команда sbm-cli contract list.
Что необходимо сделать, чтобы создать БД postgres локально? Базовый сценарий такой:
Подготовить, если еще нет, dsn для будущего подключения приложения к БД.
(Опционально) Подключиться к хосту, на котором располагается сервер БД (например docker-контейнер).
Подключиться к psql.
CREATE DATABASE …
Для разработчика, который использует платформу это одна команда sbm-cli database create.
При проектировании PaaS нам необходимо было выбрать один инструмент управления миграциями, чтобы он использовался как при локальной разработке так и в среде kubernetes. Команды sbm-cli migration up и sbm-cli migration rollback применяют или откатывают миграцию с использованием goose, а также сохраняют дамп structure.sql.
sbm-cli позволяет снизить человеческий фактор при разработке вашего приложения в части изменения контрактов. Вероятно вы встречали случаи, когда в response body удалили одно поле, после чего пострадали сервисы-консумеры. sbm-cli contract verify проверяет контракты на обратную совместимость с master веткой, а также на соответствие REST API стандарту (только для openapi).
В платформе мы выработали ряд базовых линтов golang кода, которые используются в большинстве проектов и общеприняты go-сообществом. Такие линты проверяются командой sbm-cli code lint. Линты, которые не являются базовыми, могут быть настроены в каждом проекте по решению команды.
Системные проверки в sbm-cli:
sbm-cli dependency check — проверяет корректность декларированных зависимостей.
sbm-cli manifest check — проверяет корректность заполнения configs/app.toml.
sbm-cli inframanifest check — проверяет корректность заполнения configs/values.yaml.
sbm-cli setup system-check — проверяет наличие дистрибутива engine, docker и других зависимостей на хосте.
Большая часть команд из этой категории используется в CI/CD пайплайнах, тем самым обеспечивается гарантия вызова этих валидаций.
Наша команда планирует дальнейшее развитие sbm-cli. Вот основные фичи, которые запланированы на будущий год:
Поддержка ruby проектов в Playground (пока доступно только для go и python).
Локальный запуск backend и frontend приложений одновременно в Playground среде.
Использование локального docker-контейнера в удаленной среде kubernetes.
Уровень зрелости инструмента достигает своего максимума, поэтому еще одно из направлений развития sbm-cli, которые рассматривает наша команда, — open source.
Вероятно, не все проблемы необходимо решать здесь и сейчас. Но с ростом инженерной команды компании исправление их задним числом может оказаться достаточно дорогими.
После двух с половиной лет разработки sbm-cli стал повседневным инструментом инженера в СберМаркете. Количество ежедневных вызовов sbm-cli может превышать 2400, а количество уникальных пользователей ежедневно более 210 — это около 30% нашей tech команды.
Я надеюсь эта статья помогла вам взглянуть на стандартизацию и автоматизацию процессов разработки с новой стороны.
Пишите в комментариях какая часть sbm-cli вам наиболее интересна и мы постараемся раскрыть технические детали этого компонента в одной из следующих статей цикла.
Tech-команда СберМаркета ведет соцсети с новостями и анонсами. Если хочешь узнать, что под капотом высоконагруженного e-commerce, следи за нами в Telegram и на YouTube. А также слушай подкаст «Для tech и этих» от наших it-менеджеров.