Схема CI/CD для веб-разработчиков на основе open-source инструментов

Содержание

  1. Общая схема
  2. Сервер dev с песочницами
  3. Детализация разработки (создание ветки, непрерывный деплой и тестирование, создание merge на бота, апрув в master)
  4. Прод с master-master репликацией, graylog, sentry, prometheus.

Наверное, все видели стандартную восьмёрку, как выглядит CI/CD:

Бесконечность CI/CD

Но обычно никто не рассказывает, как именно реализовать этот процесс.

Сегодня детализирую этот на примере разработки веб-сервисов.

Общая схема

На схеме мы видим, как параллельно сдаются задачи (в виде коммитов) в master-ветку.

Далее принимается решение о релизе, он фиксируется, отправляется в registry (магазин приложений), с registry готовое приложение попадает в прод. Некоторое время за ним следим (в sentry) на наличие новых ошибок. При возникновении потребности в откате - возвращаем на предыдущий тег из gitlab environments.

Далее поэтапно рассмотрим реализацию каждого шага.

Сердцем всей истории у нас является Gitlab и Gitab-CI.

Git flow показался нам слишком сложным для поддержки из одного репозитория одного проекта на продакшне. Github flow до слияния в master релизит изменения на пользователей (прод). Параллельность работы нескольких разработчиков остаётся не раскрытой.

История с production/preproduction веткой в Gitlab flow также кажется нам лишней, поэтому предлагаем вам следующую схему:

Flow

Схема поддерживает наличие нескольких разработчиков, работающих над проектом. На схеме видно, что разработка фичей идёт в неблокирующем режиме. На самом деле одного gitlab не достаточно, чтобы это работало. Грамотная архитектура проекта (кодовой базы) позволяет избежать конфликтов при разработке, что благоприятно влияет на TTM фичи. Также важно, чтобы сервис соответствовал архитектурным принципам (например, SRP). Ответственность должна быть полностью инкапсулирована в сервис.

Из факта, что большинство ошибок возникают из-за внесения изменений, следует, что максимальное внимание нужно уделить именно изменению, а именно:

  • ветка для разработки фичи максимально соответствовала проду (подход управления всем через код вам в помощь);
  • тестировать изменение;
  • проводить статический анализ и другие автоматические проверки максимально близко к изменению;
  • проводить code review;
  • по возможности наиболее строго относиться к ошибкам компилятора, интерпретаторов SQL-запросов и т.д.

Если пускать в master нестабильные изменения, разработка параллельных фич может забрать их себе и при тестировании посчитать багом, привнесённым своей фичей. Всё это может сказаться отрицательно на TTM. Поэтому важно держать master стабильным.

Процесс code review является затратным как с точки зрения фактических затрат времени, так и временного промежутка, который отдаляет фичу от master. В большом коллективе важно, чтобы правила проведения review были приняты всей командой и были объективными. Технические мероприятие для снижения длительности:

  • автоматизация проведения проверок CI вместо человека;
  • автоматическое распределение review между проверяющими;
  • автоматическая очередь мерждей после прохождения всех стадий контроля.

Dev-сервер с песочницами под каждую ветку

В начале были виртуалки на сервис

  • отдел, разрабатывающий код (Dev);
  • отдел, поддерживающий прод (Ops);
  • Ops предоставляли Dev виртуалку - копию прода. Но как только 2 разработчика начинали дорабатывать один сервис через SFTP, они перезаписывали код друг друга;
  • на проде возможно обновить только код, системный софт - невозможно (из-за трудностей с тестированием и параллельного внесения изменений).

Затем виртуалки с пушем через SVN

  • они всегда были заняты;
  • они всегда были сломаны;
  • часто не соответствовали продакшну;
  • новая виртуалка ~ 2 недели ожидания.
  • копирование файлов вручную на прод приводило к багам;

Теперь у нас Dev-сервер с песочницами под каждую ветку

Основная фишка - предоставление песочницы под задачу со всеми нужными контейнерами для разработки быстро (в идеале в течение 1 минуты после запроса). Сервис в песочнице должен максимально повторять продакшн.

Понятно, что железо стоит денег, поэтому старые песочницы ночью удаляются в автоматическом режиме. Для увеличения порядка ветки, которые не прошли проверку временем, по истечению таймаута нужно удалять. Иначе многие будут хотеть воскресить старую разработку, которая не актуальна не только по качеству кода, но и догнать master будет стоить значительного времени.

Без этой операции при большом количестве параллельных задач можно погрязнуть в хаосе.

Схема работы dev-сервера Схема работы dev-сервера

На этой картинке показано, что пользователи сервиса заходят через nginx на конкретную песочницу, которая регистрируется в nginx во время создания с помощью consul и consul-template.

Задания исполняются с помощью gitlab-ci

Первое задание - сборка образа

Build Dev Image:
  stage: build_dev_image
    - docker build --tag ${IMAGE_ADDRESS} .

Второе задание - запуск сервиса

Deploy dev:
  stage: deploy_dev
  script:
    # Для веб-сервисов нужен FQDN
    - export FQDN=task-123.project.team.dev
    - docker-compose up -d
    - consul-template -config consul.conf

Пример содержимого файла docker-compose

version: '2.3'
services:
    web:
        image: ${IMAGE_ADDRESS}
        container_name: ${COMPOSE_PROJECT_NAME}
        depends_on:
            - mongo
        network_mode: "bridge"
        environment:
            SERVICE_NAME: ${COMPOSE_PROJECT_NAME}

4. Прод с master-master репликацией, graylog, sentry, prometheus

Prod

На продакшне у нас развёрнуты kubernetes-кластера в двух географически распределённых ЦОДах. Kubernetes сейчас стандарт де-факто. DB, файлы реплицируются в обе стороны. Поддерживает IaaC (Infrastructure as a Code), что позволяет прямо в ветке внести изменения, которые с релизом уйдут на прод. Сервисы ограничены лимитами k8s, что исключает негативное воздействие одного сервиса на другой.

Географическое active-active распределение помогает нам снизить сетевые задержки до клиентов и позволяет иметь горячий бекап, куда можно переключиться при проведении работ или аварии на одном из кластеров.

С другой стороны, это достаточно дорого обходится нам (приходится писать софт соответствующим образом).

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

Контейнеры созданы по методологии 12-факторного приложения, один из пунктов которого гласит - пишите логи в стандартный вывод. Затем они подхватываются и отправляются в graylog (можно с таким же успехом взять ELK), где можно посмотреть логи.

Ошибки пишутся в sentry, при релизах просматриваются на предмет появления новых. Если в случае с graylog при ограниченном бюджете на железо ещё можно подумать о его необходимости, то для sentry не нужно много ресурсов, если вы будете своевременно устранять ошибки, которые записали. Это скажется благоприятно как на качестве приложения, так и на затратах железа на sentry. Ещё раз повторюсь, не так важно писать ошибки в sentry, как важно их разбирать и устранять.

Метрики приложений отправляются в prometheus, который в состоянии отреагировать на стандартные проблемы с сервисами. Резерв при пороговых триггерах - простой способ узнать о надвигающемся инциденте заранее и предотвратить его.