- PVSM.RU - https://www.pvsm.ru -

На РИТ 2019 наш коллега Александр Коротков сделал доклад [1] про автоматизацию разработки в ЦИАН: чтобы упростить жизнь и работу, мы используем собственную платформу Integro. Она отслеживает жизненный цикл задач, снимает с разработчиков рутинные операции и заметно сокращает количество багов в production. В этом посте мы дополним доклад Александра и расскажем, как прошли путь от простых скриптов к объединению open source продуктов через собственную платформу и чем у нас занимается отдельная команда автоматизации.
«Нулевого уровня не бывает, я такого не знаю»
Мастер Shifu из м/ф «Кунг-фу Панда»
Автоматизация в ЦИАН началась через 14 лет после основания компании. Тогда в команде разработки было 35 человек. С трудом верится, да? Конечно, в каком-то виде автоматизация все-таки существовала, но отдельное направление по непрерывной интеграции и доставке кода начало формироваться именно в 2015 году.
На тот момент у нас был огромный монолит из Python, C# и PHP, развернутый на Linux/Windows серверах. Для деплоя этого монстра у нас был набор скриптов, который мы запускали вручную. Была еще сборка монолита, приносящая боль и страдания из-за конфликтов при слиянии веток, правках дефектов и пересборке «с другим набором задач в билде». Упрощенно процесс выглядел так:

Нас это не устраивало, и мы хотели построить повторяемый, автоматизированный и управляемый процесс сборки и деплоя. Для этого нам была нужна CI/CD система, и мы выбирали между бесплатной версией Teamcity и бесплатной Jenkins, так как мы с ними работали и обе устраивали нас по набору функций. Выбрали Teamcity как более свежий продукт. Тогда мы еще не использовали микросервисную архитектуру и не рассчитывали на большое количество задач и проектов.
Внедрение Teamcity убрало только часть ручной работы: осталось еще создание Pull Request-ов, продвижение задач по статусам в Jira, выбор задач для релиза. С этим система Teamcity уже не справлялась. Нужно было выбирать путь дальнейшей автоматизации. Мы рассматривали варианты работы со скриптами в Teamcity или переход на сторонние системы автоматизации. Но в итоге решили, что нужна максимальная гибкость, которую дает только собственное решение. Так появилась первая версия внутренней системы автоматизации под названием Integro.
Teamcity занимается автоматизацией на уровне запуска процессов сборки и деплоя, а Integro сфокусировалась на верхнеуровневой автоматизации процессов разработки. Нужно было объединить работу с задачами в Jira с обработкой связанного исходного кода в Bitbucket. На этом этапе внутри Integro стали появляться свои workflow для работы с задачами разных типов.
Из-за увеличения автоматизации в бизнес-процессах выросло число проектов и run-ов в Teamcity. Так пришла новая проблема: одного бесплатного инстанса Teamcity стало не хватать (3 агента и 100 проектов), мы добавили еще один инстанс (еще 3 агента и 100 проектов), потом еще. В итоге мы получили систему из нескольких кластеров, которой было сложно управлять:

Когда встал вопрос о 4 инстансе, мы поняли, что дальше так жить нельзя, т. к. совокупные издержки на поддержку 4 инстансов уже не лезли ни в какие рамки. Возник вопрос покупки платной Teamcity или выбора в пользу бесплатной Jenkins. Мы провели расчеты по инстансам и планам по автоматизации и решили, что будем жить на Jenkins. Спустя пару недель мы перешли на Jenkins и избавились от части головной боли, связанной с поддержкой нескольких инстансов Teamcity. Поэтому мы смогли сосредоточиться на разработке Integro и допиливании Jenkins под себя.
С ростом базовой автоматизации (в виде автоматического создания Pull Request-ов, сбора и публикации Code coverage и иных проверок) появилось стойкое желание максимально отказаться от ручных релизов и отдать эту работу роботам. Помимо этого внутри компании начался переезд на микросервисы, которые требовали частых релизов, причем отдельно друг от друга. Так мы постепенно пришли к автоматическим релизам наших микросервисов (монолит пока что выпускаем вручную из-за сложности процесса). Но, как это обычно бывает, возникла новая сложность.

Из-за автоматизации релизов ускорились процессы разработки, причем частично за счет пропуска некоторых этапов тестирования. А это привело к временной потере качества. Звучит банально, но вместе с ускорением релизов нужно было менять и методологию разработки продукта. Нужно было задуматься об автоматизации тестирования, привитии персональной ответственности (тут речь про «принятие идеи в голове», а не денежные штрафы) разработчика за выпускаемый код и баги в нем, а также о решении по выпуску/не выпуску задачи через автоматический деплой.
Устраняя проблемы с качеством, мы пришли к двум важным решениям: стали проводить канареечное тестирование и внедрили автоматический мониторинг фона ошибок с автоматическим реагированием на его превышение. Первое решение позволило находить очевидные ошибки до полноценного попадания кода в production, второе уменьшило время реагирования на проблемы в production. Ошибки, конечно, бывают, но мы тратим бо́льшую часть времени и сил не на исправление, а на минимизацию.
Сейчас у нас штат из 130 разработчиков, и мы продолжаем расти [2]. Команда по непрерывной интеграции и доставке кода (далее — команда Deploy and Integration или DI) состоит из 7 человек и работает в 2 направлениях: разработка платформы автоматизации Integro и DevOps.
DevOps отвечает за Dev/Beta окружения сайта CIAN, окружения Integro, помогает разработчикам в решении проблем и вырабатывает новые подходы к масштабированию окружений. Направление разработки Integro занимается как самой Integro, так и смежными сервисами, например, плагинами для Jenkins, Jira, Confluence, а также разрабатывает вспомогательные утилиты и приложения для команд разработчиков.
Команда DI работает совместно с командой Платформы, которая занимается разработкой архитектуры, библиотек и подходов к разработке внутри компании. Вместе с этим, любой разработчик внутри ЦИАН может внести вклад в автоматизацию, например, сделать микроавтоматизацию под нужды команды или поделиться классной идеей, как сделать автоматизацию еще лучше.

Все системы, задействованные в автоматизации, можно разделить на несколько слоев:
Исходя из этой концепции мы делим зоны ответственности внутри команды DI. Два первых уровня лежат в зоне ответственности направления разработки Integro, а два последних уровня уже в зоне ответственности DevOps. Такое разделение позволяет сфокусироваться на задачах и не мешает взаимодействию, т. к. мы находимся рядом друг с другом и постоянно обмениваемся знаниями и опытом.
Сосредоточимся на Integro и начнем с технологического стека:
Мы придерживаемся принципа микросервисной разработки, хотя у нас и присутствует legacy в виде монолита ранней версии Integro. Каждый микросервис крутится в своем docker-контейнере, сервисы общаются между собой посредством HTTP-запросов и RabbitMQ-сообщений. Микросервисы находят друг друга через Consul и выполняют к нему запрос, проходя авторизацию через SSO (Keycloak, OAuth 2/OpenID Connect).

В качестве реального примера рассмотрим взаимодействие с Jenkins, которое состоит из следующих шагов:
Сейчас у нас порядка 30 микросервисов, которые можно разбить на несколько групп:
Integro автоматизирует действия, связанные с жизненным циклом задачи. Упрощенно под жизненным циклом задачи будем понимать workflow задачи в Jira. В наших процессах разработки есть несколько вариаций workflow в зависимости от проекта, типа задачи и опций, выбранных в конкретной задаче.
Рассмотрим workflow, который используем чаще всего:

На схеме шестеренка указывает, что transition вызывается Integro автоматически, в то время как фигурка человека означает, что transition вызывается вручную человеком. Рассмотрим несколько путей, по которым задача может пройти в этом workflow.
Полностью ручное тестирование на DEV+BETA без канареечных тестов (обычно так выпускаем монолит):

Могут быть и другие комбинации transition. Иногда путь, по которому пойдет задача, можно выбрать через опции в Jira.
Рассмотрим основные шаги, которые выполняются при движении задачи по workflow «Тестирование на DEV + канареечные тесты»:
1. Разработчик или PM создает задачу.
2. Разработчик берет задачу в работу. После завершения переводит ее в статус IN REVIEW.
3. Jira отправляет Webhook в сторону Jira-микросервиса (отвечает за интеграцию с Jira).
4. Jira-микросервис отправляет запрос в Flow-сервис (отвечает за внутренние workflow, в которых выполняется работа) для запуска workflow.
5. Внутри Flow-сервиса:
i) Подлив master-ветки (Git-микросервис для работы с кодом).
ii) Ветка блокируется от изменений разработчиком (Bitbucket-микросервис).
iii) Создается Pull Request на эту ветку (Bitbucket-микросервис).
iv) Отправляется сообщение о новом Pull Request в чаты разработчиков (Notify-микросервис для работы с оповещениями).
v) Запускаются сборка, тестирование и деплой задачи на DEV (Jenkins-микросервис для работы с Jenkins).
vi) Если все предыдущие пункты завершились успешно, то Integro ставит свой Approve в Pull Request (Bitbucket-микросервис).
6. Тестировщики проводят тестирование задачи. Если проблем нет, то переводят задачу в статус Ready For Build.
7. Integro «видит», что задача готова к релизу, и запускает ее деплой в канареечном режиме (Jenkins-микросервис). Готовность к релизу определяется набором правил. Например, задача в нужном статусе, нет блокировок на другие задачи, сейчас нет активных выкладок этого микросервиса и т. п.
8. Задача переводится в статус Canary (Jira-микросервис).
9. Jenkins запускает через Nomad деплой задачи в канареечном режиме (обычно 1-3 инстанса) и уведомляет о выкладке сервис мониторинга релизов (DeployWatch-микросервис).
10. DeployWatch-микросервис собирает фон ошибок и реагирует на него, если нужно. При превышении фона ошибок (норма фона рассчитывается автоматически) производится уведомление разработчиков через Notify-микросервис. Если через 5 минут разработчик не отреагировал (нажал Revert или Stay), то запускается автоматический откат канареечных инстансов. Если фон не превышен, то разработчик должен вручную запустить деплой задачи на Production (нажатием кнопки в UI). Если в течение 60 минут разработчик не запустил деплой в Production, то канареечные инстансы также в целях безопасности будут откачены.
11. После запуска деплоя на Production:
12. У разработчиков будет 30 минут на запуск отката задачи с Production в случае обнаружения некорректного поведения микросервиса. По истечении этого времени задача будет автоматически влита в master (Git-микросервис).
13. После успешного merge-а в master статус задачи будет изменен на Closed (Jira-микросервис).
Схема не претендует на полную детализацию (в реальности шагов еще больше), но позволяет оценить степень интеграции в процессы. Мы не считаем эту схему идеальной и улучшаем процессы автоматического сопровождения релизов и деплоя.
У нас большие планы по развитию автоматизации, например, отказ от ручных операций при релизах монолита, улучшение мониторинга при автоматическом деплое, улучшение взаимодействия с разработчиками.
Но на этом месте пока остановимся. Много тем в обзоре автоматизации мы охватили поверхностно, некоторые не затронули вообще, поэтому мы с радостью ответим на вопросы. Ждем предложений, что осветить детально, пишите в комментариях.
Автор: alex_kor
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/avtomatizatsiya/344893
Ссылки в тексте:
[1] доклад: https://www.youtube.com/watch?v=0wvUyjexoIg
[2] расти: https://habr.com/ru/article/469965/
[3] Источник: https://habr.com/ru/post/486056/?utm_campaign=486056&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.