Pull to refresh
217.62
Конференции Олега Бунина (Онтико)
Конференции Олега Бунина

DevOps спит, Gitlab CI работает…

Reading time12 min
Views9.1K

Можно ли построить удобный для всех pipeline, приложив усилия один раз, а не 100? Об этом расскажет Виктория Вольферц. Она работает в БКС DevOps-инженером в управлении микросервисной архитектуры. БКС предоставляет брокерские и банковские услуги для клиентов. Их основные продукты — это мобильное приложение БКС Мир Инвестиций и веб-кабинет для клиентов.

Виктория поделится опытом своей компании, как им удалось решить проблему больших временных затрат на релиз-менеджмент и Time to Market с помощью подключения проектов к CI/CD. Она расскажет о том, как они автоматизировали процессы и закрыли слабые места.

CI/CD. Теория

CI/CD — это комплекс практик и инструментов, которые помогают автоматизировать сборку, тестирование и доставку новых версий разрабатываемого продукта конечным потребителям.

CI/CD состоит из двух практик:

  1. CI – Continuous Integration (непрерывная интеграция), где происходит сборка и тестирование;

  2. CD – Continuous Delivery/Deployment (непрерывная поставка или развёртывание).

Различие Delivery от Deployment в том, что при подходе Continuous Delivery придётся нажимать кнопку, чтобы задеплоить приложение на прод, а в Continuous Deployment это происходит автоматически.

На схеме представлен полный цикл CI/CD или как его ещё называют петля CI/CD:

Он проходит в несколько этапов:

  1. пишем код;

  2. собираем;

  3. тестируем;

  4. получаем релиз кандидата;

  5. деплоим на продакшен-сервера;

  6. мониторим приложение;

  7. планируем новые фичи или доработку функционала.

Как БКС жили до CI/CD

Был репозиторий проекта, в котором лежал только код микросервиса. В нём был файл gitlab-ci.yaml, индивидуальный для каждого проекта. После того как разработчик сливал свои изменения в feature branch, запускался небольшой pipeline. В нём было 5 job’s:

  1. семантическое версионирование;

  2. валидация коммита;

  3. проверка кода;

  4. сборка;

  5. отправка артефактов в gitlab registry.

Чтобы обновить микросервис на продакшене, разработчик создавал merge request, в отдельном репозитории, где хранятся только helm charts всех проектов, с указанием новой версии приложения, которую он хочет доставить на прод. Далее, разработчик создавал задачу на DevOps’ов или писал в чат, что хочет задеплоить новую версию. DevOps-инженер проверял merge request, мёржил, и потом шёл руками обновлять сервис.

На всё это уходило от 20 до 180 минут. Потому что бывают пожары на продакшене, неполадки с инфраструктурой и прочим. Не всегда DevOps’ы могли в моменте обновить продакшен. Time to Market процесса был слишком высокий. Требовалось очень много ручных действий DevOps’ов. Поэтому решили разобрать процессы, автоматизировать и оптимизировать их.

Выявили ряд минусов.

  1. Поддержка и дебаг gitlab-ci.yaml в каждом репозитории. Когда в БКС за 2 года стало 157 репозиториев, было невероятно сложно вручную настраивать каждый.

  2. Отдельный общий репозиторий с helm charts, как результат — единый релиз. К примеру, есть 4 merge request с 4-мя разными сервисами. MR смёрджили, пошли обновлять, 3 из 4 поднялись успешно, один закрашился и не поднимается. Сразу делали helm rollback, откатывали релиз на предыдущий. Соответственно, вместе с тем, который не запустился, откатывались и те 3, которые успешно обновились — что не очень хорошо.

  3. Требовалось много ресурсов команды DevOps на релиз-менеджмент и на настройку и поддержание репозиториев в актуальном состоянии, и как результат — неэффективный Time to Market.

Тогда в БКС собрали воедино все эти проблемы и придумали пути их решения.

  1. Избавились от поддержки gitlab-ci.yaml файла в каждом репозитории. Некоторые разработчики любят добавить что-то от себя в gitlab-ci.yaml файл: прописать прокси или указать какие-то новые зависимости. И когда у них падает pipeline, они пишут DevOps’ам. В итоге каждый раз нужно было смотреть, что могли сломать в CI. На это уходило невероятное количество времени. Решили проблему так: удалили все gitlab-ci.yaml файлы со всех репозиториев сервисов и сделали в отдельном репозитории (с доступом только для devops) только два — один для Java, второй для .Net.

  2. Автоматизировали настройки репозиториев. Подключили job, который автоматически проставлял нужные нам настройки в каждом репозитории.

  3. Избавились от единого релиза для всех сервисов: 1 микросервис — это 1 релиз.  Перенесли helm charts из общего репозитория в репозитории, где лежит кодовая база сервиса. 

  4. Убрали себя из цепочки обновления, доверив это тестировщикам команд. Потому что они — это последняя инстанция, которая может сказать, что код проверен, работает и можно обновляться.

  5. Быстро подключили проект к CI/CD.

Pipeline  в БКС стал состоять из 7 stages:

  1. Автоматизация настройки и различных проверок. Это задача Repo Settings, чтобы настраивать дефолтные ветки, правила для merge request и прочее.

  2. Сборка и проверка кода.

  3. Публикация image и helm charts. Закрыли минус общего репозитория, перенесли helm charts в репозиторий с кодовой базой. Также их версионировали и сложили в Artifactory.

  4. Релиз кандидата. Создание Gitlab Release (только для ветки master)

  5. Деплой на тестовое окружение.

  6. Деплой на продакшен.

  7. Некий пост-продакшен для работы с уже запущенным подом в Kubernetes.

После этого время полного прохождения pipeline снизилось до 10 минут, максимум до 25 в зависимости от загруженности GitLab-раннеров. Сократилось и время Time to Market.

Как подключали проект к CI/CD

Зашли  в настройки CI/CD в репозитории, указали путь до gitlab-ci.yaml файла:

Файл gitlab-ci.yaml лежит в отдельном репозитории и доступен только для DevOps-инженеров. Разработчик не может добавить туда новые строчки кода.

Прежде чем перейти к подробному описанию каждой job на каждом stage, поговорим об одной переменной, которую команда БКС внедрила в процесс CI/CD. Это переменная $TEAM, она указывает к какой команде принадлежит проект. БКС её придумали и используют почти во всех jobs, которые запускаются в pipeline.

Как зародилась идея?

Раньше был чат, куда приходили алерты по всем сервисам от мониторинга Grafana. В БКС решили добавить в этот чат всех разработчиков команд, чтобы они тоже были в курсе, что происходит с их сервисами. Но разработчики не хотели видеть алерты по сервисам чужих команд , потому что им это не нужно. Они желают видеть только свои сервисы, чтобы не упустить что-то важное. Поэтому приняли решение добавить переменную $TEAM, название команды, внесли ее в variables каждого репозитория (Settings - CI/CD - Variables). И в  deployment начали ссылаться на данную переменную в лейблах.

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

Stage 1. Continuous Integration

Приступим к разбору заданий, которые запускаются в рамках CI.

Job 1. Repo Settings

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

Действия:

  • Проверка наличия и корректности переменной $TEAM.

  • Создание dev branch.

  • Настройка правил для Merge requests.

Автоматизация запускается сразу после создания репозитория. Единственное, что в БКС делают руками — это сами вносят переменную $TEAM в проект. Поскольку никто, кроме человека, не знает, какая команда разрабатывает тот или иной сервис.

Далее проверяют, что 100% внесена переменная $TEAM, поскольку она используется во многих заданиях. Создают default-ветку (dev) и настраивают правила для merge requests. Обязательно должен быть успешно выполнен pipeline и закрыты все discussions.

Job 2. Badges

Цель — быстро понять к какой команде принадлежит проект и отобразить статус последнего запущенного pipeline на default-ветке.

Действия:

  • Создание badges с названием команды ($TEAM).

  • Добавление badges из Sonarqube через API.

Badges - информативные плашки в проектах, в которые можно вывести любую нужную информацию. Первый badges, который создали в БКС — это badges TEAM, чтобы просто заходить в проект и сразу видеть, к какой команде он принадлежит. Тем самым избавили аналитиков от рутинной работы ведения списка ответственных команд в Confluence. Теперь из variables проекта тянется переменная TEAM, создаётся кастомный badges с помощью утилиты Anybadge. Этот проект есть на GitHub.

Также в БКС тянут уже готовые badges с SonarQube, которые показывают статус последнего пройденного pipeline на default-ветке проекта. Теперь главная страница выглядит информативно.

Job 3. Sentry

Цель — узнавать о проблемах раньше, чем клиент напишет в поддержку, находить источник ошибки и причину, связывать релиз микросервиса с ошибками.

Действия:

  • Создание команды ($TEAM) и проекта.

  • Настройка интеграции для отправки алертов в Rocket Chat.

  • Запись переменной SENTRY_DSN в проект.

Sentry — это суперкрутая программа для агрегации exceptions, для работы с ошибками. Здесь можно по stack trace определить, какая строчка кода могла создать проблему в сервисе. В Sentry есть абсолютно всё. Виктория считает, что это серебряная пуля в мониторинге микросервисов и не только. Её используют как веб-разработчики, так и DevOps.

БКС создают команду в Sentry, к ней привязывают проект, чтобы слать алерты только по сервисам, которые разрабатывает та или иная команда. Далее настраивают webhook, в случае БКС это webhook для Rocket Chat (корпоративного мессенджера) и записывают переменную SENTRY_DSN в проект. Это ссылка, по которой микросервис понимает, куда ему нужно отправлять алерты.

Job 4. Must Have Check

Цель — проверять то, что важно.

Действия:

  • Запуск простой проверки, написанной на bash, проверка наличия файлов/строк.

К примеру, проверка описания проекта, Docker-файл. Всё, что похоже на пароли, должно быть замаскировано, либо лежать в секретах в Vault, то есть не должно быть никаких открытых паролей. Также подключение проб готовности пода: /readiness, /liveness; скриншоты успешного или неуспешного прохождения. В случае неуспешного прохождения выходит ошибка с информацией чего не хватает и где посмотреть. В данном случае это канал DevOps, где написана вся важная информация.

Job 5. Lint Helm Charts

Цель — проверить, что helm charts написаны верно, нет ошибок рендера.

Действия:

  • Использовать helm template, helm lint.

  • Проверить для всех окружений.

  • Запустить при любом изменении в директории helm/.

Нужно проверить, что все переменные, объявленные в сущностях в папке template, 100% есть в values-файлах. Для этого все values-файлы для тестового окружения, pre-prod и продакшена прогоняют через helm template и получают готовые helm charts для трёх окружений. Проходят по ним Helm Lint — всё, проверили!

Это задание запускают не просто так, а только при изменении директории helm. 

Job 6. Versioning

Цель — рассчитать версию кода микросервиса и связать её с определённой версией сборки helm charts.

Действия:

  • Семантическое версионирование.

  • Добавление ревизии — версии сборки helm charts.

В БКС есть шаблон написания коммита, который соблюдают разработчики:

LK-***[TYPE]: description commit

Здесь:

  • *** — номер задачи в Jira;

  • TYPE — масштаб изменений.

Масштаб изменений может быть разным. Ранее уже было внедрено семантическое версионирование на основе трёх обязательных номерных версий: MAJOR — новый сервис; FEATURE — крупный блок нового функционала; MINOR — небольшие изменения. Также добавили коммит BYPASS. Он используется для всех коммитов на фиче ветки, кроме первого, то есть он не влияет на расчёт версии.

После перехода на CI/CD, была добавлена ревизия. Это число, которое идёт через дефис после основной версии. То есть версия сборки helm charts. Всё это также версионируется, привязывается к определённой версии сервиса. Предыдущие нигде не хранятся.

Версионирование работает так: каждый раз, когда запускается эта задача, счётчик равен 0000. В БКС в хронологическом порядке берут все commit message, высчитывают, какая должна быть версия кода и charts. В результате получаются две переменные:

  1. APP VERSION 1.3.12, которая включает в себя только версию кодовой базы;

  2. CHART VERSION 1.3.12-22 — кодовая база плюс версия сборки helm charts.

То есть привязывают рабочую версию приложения к charts. На выходе получается 100% рабочая сборка.

Job 7. Check Endpoint

Цель — не сломать продакшен.

Действия:

  • Отрисовать с помощью helm template готовый Ingress-манифест в текущем проекте.

  • Получить через API-kubernetes все пути, которые есть на проде по всем сервисам.

Есть трафик от клиентов и Ingress-контроллер, который маршрутизирует трафик по сервисам в Kubernetes. Поскольку микросервисов в БКС очень много, невозможно вести страничку в Confluence, где будут указаны все endpoints. Чтобы аналитики или разработчики, когда придумывают, по какому endpoint будет доступен сервис на проде, заходили и смотрели, что сейчас такого же нет.

В БКС написали эту задачу сами на Python. Они рендерят с помощью Helm Template готовый Ingress-манифест. Через API Kubernetes дёргают все endpoints, которые сейчас существуют на проде по всем namespaces. Сравнивают в текущем сервисе, какие придуманы новые, и всё, что есть. Если находятся совпадения, то пишут ошибку в job, что endpoint такой же, как в этом сервисе. Дальнейшие задания не запускаются, пока не будет исправлено.

Stage 2. Сборка и проверка кода

Job 1. Build

Цель  — получить артефакт сборки кода.

Действия:

  • Использовать подход Docker in Docker.

  • Компилировать код проекта  — результат .jar-файл.

  • Выполнить unit-тесты.

Здесь используют подход Docker in Docker, компилируют код, проводят unit-тесты и складывают в GitLab Registry. Совсем недавно БКС добавили надстройку на GitLab-раннерах, чтобы сборка осуществлялась в оперативной памяти, так как они не используют хранилища. Добавили ещё S3 Minio Cache. Буквально через 2-3 минуты получился собранный и проверенный артефакт.

Job 2. Dependency-scan and SonarQube

Цель — проанализировать качество кода микросервиса и проверить зависимые библиотеки на известные уязвимости на основе данных из NVD.

Действия:

  • Автоматически создать проект с настройками Quality Gate и Quality profile при первом запуске SonarQube.

  • По результатам Dependency Scan сгенерировать отчёт и отправить в SonarQube.

SonarQube сам проверяет код, Dependency Scan проверяет все подключённые библиотеки в микросервисе на известные уязвимости на основе БД уязвимостей NVD. Если какая-то уязвимость находится в рамках Dependency Scan, он складывает это всё в SonarQube. Далее генерирует этот артефакт в формате JSON и также через API посылает его в SonarQube.

На картинке указана уязвимость из интернета — Log4j, которую в БКС исправили:

Stage 3. Публикация

Job 1. Publish Helm Charts

Цель — упаковать helm charts и отправить в Artifactory.

Действия:

  • helm package —app-version=1.3.12—version=1.3.12-22;

  • отправить в Artifactory.

В БКС используют утилиту Helm Package, указывают APP version — версию кодовой базы и ревизию charts (версия сборки helm charts).

Job 2. Publish Image

Цель — собрать готовый docker-образ микросервиса.

Действия:

  • Вычислить тип коммита — собрать образы.

  • Отправить в Gitlab Registry.

Здесь собирают Docker-образы и складывают их в GitLab Registry по стандартной практике.

Stage 4. Релиз

Цель — связать релиз (версию микросервиса) с задачей в Jira, для отслеживания истории изменений.

Действия:

  • Использовать Gitlab Release API.

  • Создать релиз, включающий в себя: исходный код репозитория; ссылку на задачу, в рамках которой были внесены изменения в код и собрана новая версия; ссылку на созданный tag.

На данном этапе БКС создают единую страничку в GitLab, где будет вся информация по релизу, кодовая база, ссылки.

Благодаря тому, что есть единое описание коммитов, которое выглядит как: LK-***[TYPE]: description commit, можно сделать ссылку на задачу в Jira. В релизе есть исходный код, ссылка на задачу, по которой были внесены изменения. На неё можно кликнуть, попасть в Jira, посмотреть, какие изменения были, что за задача, кто заказчик и прочее. Также посмотреть все изменения в коде и все коммиты. На этом стадия Continuous Integration завершена.

Stage 5. Continuous Delivery

На этом этапе происходит деплой на тестовое окружение.

В БКС права есть только у тестировщиков. Но разработчики, хотят выкатывать прямо с фичи-ветки, задеплоить и проверить, как работает их код. Поэтому в БКС сделали кнопочку Deploy Feature. Она доступна только для разработчиков. Здесь не присваивается никакой номер версии, используют как версию имя фичи ветки.

Для деплоя на тест, есть Test Update и Pre-Prod Update. Здесь уже деплоится непосредственно версия, которая собралась и рассчиталась в рамках ранее пройденных job.

Stage 6. Production

Есть кнопка Prod Update, доступная только для тестировщиков. Также, в БКС есть основной и резервный namespace. Для чего? Некоторые сервисы должны смотреть, например, на два разных сервера для торгов, поэтому их задублировали в двух разных окружениях. Получается, нужно обновлять одновременно основной продакшн namespace и резервный.

Если этот сервис задублирован на втором окружении, когда нажимают на кнопку Prod Update, в БКС проверяют, что на основном окружении все поды успешно поднялись. Они ждут какое-то время, и только потом запускают обновление на резервном окружении.

Чтобы понять, что сервис задублирован, в БКС добавили в variables проекта переменную, которую чекают в начале задания. Если она есть, то понятно, что сервис задублирован.

Следующая job — это Prod Rollback. В рамках неё откатывают релиз на предыдущий. Эта кнопка тоже доступна только для тестировщиков в случае неуспешного выката.

Последняя кнопка Prod Remove — это полное удаление релиза. Она нужна в pipeline, потому что бывает такое, что микросервис просто устарел. Эта функциональность не нужна и этот процесс не развивают. Чтобы не идти в консоль и не делать ничего руками, было решено тоже это автоматизировать. Кнопка доступна только для DevOps-инженеров.

Stage 7. Post production

Цель — получить Thread/Heap dump с запущенного пода Java-микросервиса для дебага утечки памяти.

Действия:

  • запустить pipeline на любой ветке (var $POD);

  • кинуть оповещение команде в чат.

Эта кнопка в БКС появилась после того как, разработчики начали приходить с просьбой снять Thread или Heap dump с Java-машины, с уже запущенного пода на проде. Например, к ним приходили алерты, что память сервиса ушла в потолок или был низкий RPS. Возникла потребность это дебажить, смотреть распределение потоков. На всё могло уйти от 5 до 15 минут, в dump уже могло не оказаться нужной информации. Требовалось ускорение процесса. Поэтому решили его автоматизировать.

Эта задача запускается на любой ветке проекта. Разработчик сам может запустить pipeline с указанием переменной пода, с которой он хочет снять dump. Далее запускается команда удалённого управления. В рамках прохождения job снимается dump, складывается в хранилище и направляется алерт в чат команды, в котором указана информация: какие dump сняты; их количество; с какого пода. Также в алерте есть кликабельная ссылка, по которой можно пройти и скачать dump. На это уходит буквально 1-2 минуты.

Итог

Для уменьшения времени на релиз-менеджмент и сокращения Time to Market команда БКС сделала следующее:

  • Автоматизировали всё, что можно, кроме добавления переменной в самом начале.

  • Закрыли слабые места — такие, как единый релиз и пересечение путей API gateway на проде.

  • Написали два универсальных gitalb-ci.yaml файла для разных языков.

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

Как говорил Авраам Линкольн:

«Дайте мне шесть часов, чтобы срубить дерево, и я потрачу первые четыре на заточку топора»

Tags:
Hubs:
Total votes 8: ↑8 and ↓0+8
Comments3

Articles

Information

Website
www.ontico.ru
Registered
Founded
Employees
11–30 employees
Location
Россия