DOU Labs: как в EPAM сделали opensource-инструмент для развертывания serverless-приложений
В рубрике DOU Labs мы приглашаем IT-компании делиться опытом собственных интересных разработок и внутренних технологических инициатив. Вопросы и заявки на участие присылайте на Данный адрес e-mail защищен от спам-ботов, Вам необходимо включить Javascript для его просмотра. .
Привет, меня зовут Владислав Терещенко, я сотрудничаю с EPAM как Software Engineer. Эту статью мы готовили вместе с коллегами Александром Оньшой и Александрой Романенко. Расскажем вам, как сделали Syndicate Deployment Framework для AWS.
Эта статья наверняка будет небезразлична тем, кто пробует работать или уже плотно работает с serverless-приложениями. Мы с ними сражаемся уже третий год. Так вышло, что мы начали делать свой фреймворк для их деплоймента, когда на рынке были единицы подобных решений. Сегодня их значительно больше. Но мы все же завершили проект. И будем рады подискутировать, почему не отдали предпочтение аналогам, а заморочились сами.
А для тех, кто только присматривается к serverless, мы расскажем о препятствиях, которые могут поджидать и вас.
Основная идея, или от локальной проблемы к отдельному тулу
Если коротко, наш Syndicate — это фреймворк для Amazon Web Services, который позволяет легко развертывать serverless-приложения, используя метаописания ресурсов. За основу взяли то, что инструмент должен:
- Быть простым.
- Работать быстро.
- Уменьшать вероятность ошибки в коммуникации между разработчиком и девопсом.
Как это часто бывает, изначально эта штука не была самостоятельной. В 2016 году, во время работы над большим SaaS-проектом, мы решили попробовать хайповый serverless. Взяли одно из маленьких приложений проекта и переписали его, используя AWS Lambda (дальше просто лямбда). В процессе переписывания мы придерживались принципа single responsibility: каждая функция должна выполнять логически отделимую часть работы, не храня при этом состояние.
Основной профит serverless в том, что в таком случае мы не платим за простой инфраструктуры. Пока нет пользователя, ресурсы приложению не нужны. Удобно и экономно.
Но здесь же и обратная сторона медали. Проблема любого девелопера — инструмент нужно тестировать. В традиционном подходе мы пишем код, запускаем его локально, дебажим — и все хорошо.
В serverless с лямбдами так не получится. Amazon разворачивает код в контейнере, к которому нет доступа. Весь дебаг, по сути, идет в голове. Никто не отбрасывает возможность написания unit- и integration-тестов. Но, как обычно, просчитать все ошибки заранее невозможно.
Сначала нам нужно было деплоить небольшое количество ресурсов: несколько DynamoDB-таблиц и около 5 AWS Lambda и ролей для них. Настал момент, когда конфигурировать этот «зоопарк» стало дольше, чем писать новую лямбду. Так появился Python-script на несколько десятков строк, который деплоил это за нас. По мере использования новых сервисов наша тула росла: мы ее расширяли, добавляя возможность создавать новые типы ресурсов.
В итоге скриптики доросли до того, что мы увидели возможность оформить их в отдельный CLI tool. По задумке, Syndicate должен был помочь не только нам в свете этого проекта, но и другим разработчикам в различных похожих кейсах. Результат вы можете видеть на GitHub. Да, написано все на Python.
Наш фреймворк подходит для разработки любого serverless-проекта, который вы хотите разворачивать на Amazon с использованием AWS Lambda, и ресурсов, наиболее популярных при serverless-разработке: SQS, DynamoDB, Step Functions, API Gateway и т. д.
Сейчас Syndicate используется в том большом переписанном проекте SaaS-решения. Разработка с Syndicate ведется на протяжении 3 лет, и сам продукт уже подходит к фазе релиза.
Как пользоваться «Синдикатом»
По ссылке на GitHub вы увидите проект и простой гайд. Здесь — подробное описание, как фреймворк работает под капотом, что нужно написать в темплейте, чтобы задеплоить какую-то специфическую вещь, а также используемые концепции.
Работа состоит из трех шагов.
Первый — создание configuration-файла. В нем описаны все атрибуты, необходимые Syndicate для взаимодействия с инфраструктурой: AWS Account ID; роль, которую будет использовать фреймворк; регион, где будет развернуто приложение; пути к модулям, которые нужно паковать в лямбды (об этом дальше) и т. д.
Второй шаг — использование Syndicate в проекте. Если это Java-проект, необходимо добавить Syndicate maven plugin в pom.xml модулей, которые содержат в себе lambda handlers. Это нужно для генерации метаописаний лямбд по аннотациям, которые предоставляет Syndicate. Таким образом, Syndicate дает возможность описывать лямбда-функции in Java way.
Если это Python-проект, нужно создать метаописание лямбд, перечислить external- и internal-зависимости функции — и все взлетит.
В нашем случае, кроме лямбд, есть еще множество ресурсов, с которыми лямбды взаимодействуют. Все они должны быть описаны в файле deployment_resources.json. Этих файлов может быть несколько и лежать они могут по всему проекту: все будут собраны в один большой файл-темплейт, который будет процессить Syndicate. Обычно мы создаем эти темплейты возле тех лямбд, которые используют описанные в них ресурсы.
Завершается шаг сборкой так называемого bundle — набора упакованных deployment packages-лямбд — и файла-темплейта с описанием инфраструктуры.
Третий шаг — это создание ресурсов. Достаточно вызвать одну
А как же аналоги? В чем отличия? В чем профит?
Это, наверное, самая непонятная часть. Зачем вообще было тратить время на разработку чего-то, что и так уже давно есть?
Действительно, уже в 2015 году можно было использовать родное решение от Amazon — CloudFormation, которое начало поддерживать AWS Lambda. Но на тот момент оно не поддерживало часть сервисов, которая была нам нужна в разработке SaaS-решения.
Другая тула — Terraform. Она тоже в каком-то формате описывает инфраструктуру и деплоит ее. К тому же в Terraform можно описать инфраструктуру для AWS, Azure, Google и многих других вендоров.
Мы же смотрели не на сам инструмент, а на концепт.
Основной идеей Syndicate было сделать взаимодействие разработчика и девопса (или любого, кто ответственен за инфраструктуру на проекте) более продуктивным. Не допустить miscommunication при объяснении необходимого сета ресурсов для работы среды или обычных typo в темплейтах.
Поэтому Syndicate генерирует метаописание для лямбды сам. А описание тех ресурсов, мета которых не генерируется, ложится на плечи разработчика. Но мы и далее работаем над тем, чтобы все больше ресурсов можно было описать с помощью средств, привычных для разработчиков (вроде аннотаций).
Так у нашего инструмента появилось небольшое, но очень важное дополнение — Maven plugin, который генерирует по аннотациям описание инфраструктуры. Это типичный подход джавистов. То есть мы пишем над каким-то классом аннотацию @LambdaHandler, описываем все необходимые параметры и у нас появляется JSON, который скажет Syndicate, как правильно развернуть эту лямбду в AWS. В этом и был смысл: чтобы не описывать инфраструктуру в двух местах и чтобы описывал ее один и тот же человек.
Преимущества очевидны:
- Так быстрее.
- Мы не тратим время на коммуникацию двух или нескольких человек.
- Уменьшается вероятность ошибки: я указал что-то в аннотации и могу в коде на это ссылаться, а в темплейте оно сразу прорастет.
Еще у Syndicate упрощенная схема метаописаний ресурсов. Вам нужно будет написать меньше информации в темплейте, но вы получите тот же результат, как если бы вы описывали инфраструктуру в CloudFormation.
Касательно использования AWS-аккаунтов. Syndicate управляет ресурсами на уровне бандла. Бандл может быть задеплоен в аккаунт, где уже могут быть созданы какие-то ресурсы.
После деплоя Syndicate описывает все созданные ресурсы и хранит описание у себя. Это нужно для того, чтобы удалять только те ресурсы, которые деплоили, а также для модификации инфраструктуры.
Напоследок о скорости. SaaS-решение, о котором мы уже упоминали, сейчас состоит примерно из 270 лямбд, 150 IAM policies, 170 IAM roles, 60 DynamoDB tables, 3 SQS queues, 60 SNS topics, 70 CloudWatch rules, 1 API Gateway с 300 ресурсами, 8 State machines. Все это суммарно деплоится около 40 минут.
Если сравнивать с Terraform или CloudFormation, это хороший показатель. Захоти мы перевести проект на тот же CloudFormation, заимели бы много проблем. У нас слишком большая инфраструктура, а у CloudFormation ограничение в 200 ресурсов на 1 темплейт — не очень удобно. Ведь мы хотим, чтобы эти темплейты у нас были отвязаны друг от друга, но в то же время собирались в нечто единое.
Сложности и факапы
Здесь, к сожалению (или к счастью), ничего нового. Все ошибки закрадывались из-за невнимательности и усталости.
Бывало, правда, и такое: Amazon вдруг временно начал возвращать что-то недокументированное. Наш SaaS-проект использует Syndicate минимум 2 раза в день для DEV-энва. Инфраструктура деплоится утром. А вечером он вызывается, когда инфраструктура чистится для экономии костов. Неприятно, когда утром это работает, а очистку сделать не получается, потому что, например, со стороны Amazon прилетает какая-то ошибка или оказывается опечатка в коде. Так что иногда приходилось изворачиваться.
Апдейты и планы: методология по serverless и (тс-с-с) дебагер
Syndicate изначально планировался просто как Infrastructure-as-Code-инструмент. Но на момент, когда мы вышли в open source, аналогов уже было явно не два. Все преимущества нашего варианта мы описали выше. Но на этом не останавливаемся.
В начале мы говорили, что у нас было много неудобств, связанных с разработкой под serverless. Мы не можем дебажить и мониторить весь проект. Что можем, проверяем локально. Остальное просто деплоим и смотрим, как оно себя ведет. Конечно, было бы хорошо, чтобы были инструменты и стандарты, помогающие разрабатывать такие приложения.
Сейчас мы работаем над тем, чтобы превратить Syndicate в платформу для разработки serverless-систем. Дать набор инструментов и подходов. Мы в процессе интеграции с JetBrains IntelliJ IDEA: было бы удобно интегрироваться в саму среду разработки, чтобы помогать мониторить environment.
Дальше — коммуникация девелопера и девопса. Под serverless нужны определенные специфические знания, связанные именно с AWS. Девопс обычно требует от разработчика каких-то понятий: сколько лямбда будет требовать памяти, насколько ее нужно распараллелить и прочую специфику. Одна из наших задач — предугадать все моменты, которые требуют от разработчика специфического знания.
Скорее всего, будет задан минимально необходимый оптимальный сет, при котором будет работать большинство проектов. Настройки нужно сделать интуитивно понятными, чтобы не копаться в тысяче параметров AWS и не сидеть над этим часами вместе с девопсами. Для девелопера меньше конфигураций — меньше головной боли. Максимально просто и удобно.
А еще у нас есть смелая цель — замахнуться на то, чтобы помочь разработчикам дебажить serverless-приложения, развернутые в AWS-аккаунте. Это поможет выиграть много времени. Мы, например, его теряли как раз на том, что предполагали, что оно будет работать правильно.
Здесь можно возразить, что за 3 года появились решения, которые позволяют дебажить лямбду локально: SAM Local, Local Stack и т. п. Для одной — отлично. А теперь представьте: вы разрабатываете какую-то распределенную систему со множеством компонентов. Она спроектирована с Event Sourcing-подходом. Например, есть лямбда, которая пишет в DynamoDB таблицу, а на эту запись вызывается другая лямбда. Как такое эмулировать локально? Нужен дебаг, который будет работать с реальной средой, когда ивент будет от AWS.
Вероятно, AWS и сам движется к созданию такого дебагера. Но мы развиваемся параллельно и можем стать достойной альтернативой.
Поконтрибьютим вместе?
Сейчас наша микрокоманда состоит из трех человек: меня, Александра Оньши и Владислава Кулика, который также сотрудничает с EPAM как Software Engineer. Мы адаптируемся к тому, что предлагает рынок. Пробуем сделать решение, которое будет опережать его потребности.
Слева направо: Владислав Кулик, Александр Оньша, Владислав Терещенко
Мы сами пишем эту систему и используем ее. И хотя изначально делали Syndicate под конкретный большой проект, пытались учитывать мнения разных технических сторон: знакомых, друзей, архитекторов, внешних клиентов. Чем больше будет сообщество, которое будет видеть, что пожелания учитываются, тем больше будет идей. И тем больше разных проблем мы сможем решить.
Мы изначально не хотели делать фреймворк закрытым: нам интересно сделать продукт, которым будут пользоваться. Поэтому если у вас появятся пожелания и/или замечания, мы всегда открыты. Хотите сами сделать реализацию? Welcome, мы добавим ваш кусочек в Syndicate, а вы присоединитесь к числу контрибьюторов. Напоминаем: посмотреть на фреймворк можно здесь.
Всем fearless, careless и serverless!