В предыдущей статье мы обзорно рассмотрели основные компоненты CI/CD Kubernetes платформы Gitorion. В данной статье подробнее остановимся на реализации хостинга кода, системы управления версиями и непрерывной интеграции CI.
Абстрактная постановка задачи
Абстрактно задача прозвучала так:
Подобрать и установить Git-сервер в Self-hosted исполнении, чтобы не зависеть от коммерческих и облачных решений;
Организовать совместное внесение правок в код группой разработчиков так, чтобы они не мешали друг другу;
Предусмотреть возможность предварительной демонстрации внесенных изменений руководству;
Разработать механизм доставки внесенных изменений в продакшен после одобрения руководством;
Максимально автоматизировать все процессы;
Проработать возможность отката до предыдущих версий в случае ошибок.
Выбор хостинга кода и системы управления версиями
После непродолжительного поиска нашли легковесный Open-Source продукт Gitea, реализующий функции хостинга кода и совместной разработки на базе Git. Gitea создан как Self-hosted решение, однако на нем также запущен публичный хостинг кода Codeberg. В 2022 году был взят курс на коммерциализацию Gitea, что вошло в противоречие с п.1 поставленной выше задачи. В ответ на коммерциализацию Gitea, часть разработчиков сделала форк Forgejo, который будет оставаться независимым, принадлежать сообществу, иметь независимую кодовую базу и развиваться самодостаточно. Мы заменим Gitea на Forgejo и напишем об этом отдельную статью. Ниже рассмотрим решения на базе функционала Gitea, поскольку тот же самый функционал есть и в Forgejo.
Распределение Git-веток по контурам
Начали с создания 3х изолированных контуров (они же namespase в Kubernetes) - development, staging и production с идентичным набором микросервисов (frontend, backend, mysql/postgresql, redis и т.д) в каждом из контуров.
development - контур для разработчиков. Каждый программист создает свою под-ветку от main-ветки и вносит изменения в код проекта только в пределах своей под-ветки. Выполнив задание, делает push в Gitea. Gitea шлет Web-хук в Jenkins. Jenkins собирает Docker-контейнер микросервиса с кодом данного программиста и доставляет в динамическое окружение на review. Так мы решили вторую задачу.
staging - контур для демонстрации изменений руководству. Изменения из веток программистов тимлид организованно вливает в main-ветку и делает push в Gitea. Gitea так же шлет Web-хук в Jenkins, который собирает Docker-контейнер и доставляет в staging контур для демонстрации руководству. Так мы решили третью задачу.
production - продакшен контур. После одобрения руководством тимлид вручную запускает пайплайн в Jenkins, выполняющий промоушен Docker-образа из staging контура в production контур. Так мы решили четвертую задачу, но это скорее относится к непрерывной доставке CD, о которой речь пойдет в следующей статье
Порядок действий разработчика
Тимлид создает новому программисту аккаунт в Gitea (например user3).
Делает разработчика соавтором репозитория микросервиса, в код которого программист будет вносить изменения.
Программист user3 клонирует Git-репозиторий, создает под-ветку (например dev1).
И приступает к выполнению задания. Добавляет правки в код, делает push-в свою ветку. Jenkins автоматически собирает Docker-образы микросервиса с правками программиста и доставляет его на review в development контур. Предварительные результаты работы можно оценить по ссылке https://review-frontend-dev1.example.com (dev1 - ветка разработчика).
Выполнив задание, программист user3 создает запрос Pull Request на вливание изменений из своей ветки dev1 в main-ветку и докладывает тимлиду о выполнении задания.
Красным показан код, который разработчик удалил, а зеленым код, который добавил. Для примера мы просто сменили версию в коде сайта.
Порядок действий тимлида
В личном кабинете тимлида появится запрос на слияние от разработчика user3.
Тимлид выбирает запрос на слияние и получает подробную информацию о нем.
Переходит на вкладку "Измененные файлы" и изучает внесенные программистом правки.
Если все в порядке, и программист верно выполнил задание, тимлид нажимает на кнопку "Cоздать коммит на слияние" и вливает изменения из ветки разработчика dev1 в main-ветку. В случае успешного слияния появится такое сообщение.
Коммит на слияние инициирует Web-хук из Gitea в Jenkins. Jenkins автоматически соберет Docker-образ и доставит контейнер с наработками программиста в staging-контур, где тимлид сможет продемонстрировать внесенные изменения заказчику проекта.
Автоматизация
Для автоматизации задействовали механизм Web-хуков в Gitea и Jenkins. Все, что нужно сделать программисту или тимлиду для внесения изменений в микросервис, это добавить правки в код и сделать push. Дальнейшие процессы происходят автоматически. Gitea, получив push, посылает Web-хук в Jenkins. Jenkins по Web-хуку вытягивает Git-репозиторий из Gitea и запускает пайплайн для микросервиса, стадии которого заданы в Jenkinsfile. Компилирует код приложения, если микросервис написан на компилируемом языке программирования, или просто копирует код в Docker-образ, если на интерпретируемом языке. Cобирает Docker-образ в соответствии со слоями, заданными в Dockerfile, и помещает в приватный репозиторий Docker Registry. Доставляет микросервис при помощи helm в кластер Kubernetes. За всеми этими процессами можно наблюдать в Web-интерфейсе Jenkins и оценить время выполнения как всего пайплайна, так и отдельных его стадий.
Добавить web-хук можно в настройках репозитория.
Выберите Web-хук типа Gitea, задайте URL сервиса Jenkins и токен доступа.
Защита веток
Сделав программиста соавтором, тимлид дает ему право вносить изменения не только в свою ветку, но и в main-ветку. Если все программисты будут неконтролируемо вносить изменения в main-ветку напрямую, начнется путаница и конфликты, и мы не выполним требование в п.2 поставленной задачи. Перейдите в настройки репозитория и создайте правила защиты веток.
Для ветки main cоздайте правило, разрешающее прямое внесение правок и вливание изменений Pull Request Merge только пользователям из белого списка (тимлидам, руководителям проекта).
Платформа построена в соответствии с подходом инфраструктура как код IaC. В одном Git-репозитории рядом с исходным кодом микросервиса хранятся: Dockerfile для сборки Docker-образа микросервиса, Jenkinsfile с пайплайном сборки и доставки, конфигурационные файлы микросервиса для всех 3х контуров, helm-чарт развертывания микросервиса в кластер Kubernetes.
Чтобы программисты не "сломали" процессы сборки и доставки, мы ограничили им доступ ко всем файлам и директориям репозитория, кроме директории src/ с исходным кодом микросервиса, с которым программисты будут непосредственно работать. Создали правило для всех веток с префиксом dev** и перечислили директории и файлы, к которым доступ программистам запрещен.
Заключение
В следующей статье мы рассмотрим подробнее тонкости реализации непрерывной доставки CD при помощи Jenkins, а также вспомогательные инструменты, которые потребовалось интегрировать в платформу для построения Continuous Delivery. Спасибо.