GitLab CI для непрерывной интеграции и доставки в production. Часть 1: наш пайплайн

в 5:52, , рубрики: continuous deployment, continuous integration, devops, Git, gitlab, gitlab ci, open source, Блог компании Флант, системы сборки, Системы управления версиями

GitLab CI для непрерывной интеграции и доставки в production. Часть 1: наш пайплайн - 1

Итак, GitLab CI: что можно ещё рассказать о нём? На хабре уже есть статьи про установку, про настройку раннеров, про командное использование, про GitLab Flow. Пожалуй, не хватает описаний того, как используется GitLab CI в реальном проекте, где задействовано несколько команд. А в современном мире разработки ПО это действительно так: ведь есть (как минимум) разработчики, тестировщики, DevOps- и релиз-инженеры. С подобным разделением на команды мы работаем уже несколько лет. В этой статье я расскажу о том, как мы, используя и улучшая возможности GitLab CI, реализовали и применяем в production для коллектива из нескольких команд процессы непрерывной интеграции (CI) и отчасти доставки приложений (CD).

Наш пайплайн

Если вы сталкивались с CI-системами ранее, то понятие пайплайна вам знакомо — это последовательность выполнения стадий (здесь и далее в статье для термина stage использую перевод «стадия»), каждая из которых включает несколько задач (здесь и далее в статье job — «задача»). От момента внесения изменений в код до выката в production приложение по очереди оказывается в руках разных команд — подобному тому, как это происходит на конвейере. Отсюда и возник термин pipeline («конвейер» — один из вариантов дословного перевода). В нашем случае это выглядит так:

GitLab CI для непрерывной интеграции и доставки в production. Часть 1: наш пайплайн - 2

Краткие пояснения по используемым стадиям:

  • build — сборка приложения;
  • testing — автотесты;
  • staging — развёртывание приложения для разработчиков, DevOps, тестировщиков;
  • pre-production — развёртывание в «предварительный production» для команды тестировщиков;
  • approve — «предохранитель», благодаря которому релиз-инженер заказчика может отказать в развёртывании на production определённого тега;
  • production — развёртывание на production.

Примечание: Нет ничего совершенно универсального, поэтому для вашего конкретного случая этот пайплайн скорее всего не подходит: он либо избыточен, либо прост. Однако цель статьи не описывать единственно верный вариант, подходящий каждому. Цель — рассказать на примере о том, как можно работать в GitLab CI нескольким командам и какие возможности есть, чтобы реализовать такой пайплайн. На основе этой информации можно разработать свою собственную конфигурацию GitLab CI.

Как это используется?

Начну с рассказа о пайплайне с точки зрения его использования — то, что можно назвать user story. Тут выяснится, что на самом деле пайплайна у нас даже два: укороченный для веток и полноценный для тегов. И вот как выглядят эти последовательности:

  1. Разработчики выкладывают код приложения в ветки с префиксом feature_, а DevOps-инженеры — код инфраструктуры в ветки с префиксом infra_. Каждый git push в эти ветки запускает процесс сборки приложения (стадия build) и автоматические тесты (стадия testing).
  2. Задачи на следующих стадиях не вызываются автоматически, а определены как задачи с ручным запуском (manual).
  3. На стадии staging можно запустить задание и выкатить собранное и протестированное приложение на упрощенное окружение. Это могут делать разработчики, DevOps-инженеры, тестировщики. При этом для выката на окружения тестировщиков должны быть пройдены все тесты.
  4. После успешного прохождения тестов и выката на одно из окружений staging можно выкатить приложение в pre-production — это делают только тестировщики, DevOps-инженеры или релиз-инженеры.
  5. По мере накопления успешно протестированных фич релиз-инженер готовит новую версию и создаёт в репозитории тег. Пайплайн для тега отличается от пайплайна для ветки двумя дополнительными стадиями.
  6. После успешной сборки, тестов и выката в pre-production проводятся дополнительные ручные тесты новой версии, показ заказчику и другие «издевательства» над приложением. Если всё прошло успешно, то релиз-инженер запускает задание approve. Если что-то пошло не так, то релиз-инженер запускает задание not approve.
  7. Выкат приложения на production возможен только после успешного выката на pre-production и выполнения задания approve. Выкат на production может запустить релиз-инженер или DevOps-инженер.

GitLab CI для непрерывной интеграции и доставки в production. Часть 1: наш пайплайн - 3
Роль релиз-инженера в пайплайне

Пайплайн и стадии в деталях

Задачи на стадии build собирают приложение. Для этого мы используем свою разработку — Open Source-утилиту dapp (о её основных возможностях читайте и смотрите в этой статье + видео), которая хорошо ускоряет инкрементальную сборку. Поэтому сборка запускается автоматически для веток с префиксами feature_ (код приложения), infra_ (код инфраструктуры) и тегов, а не только для нескольких традиционно «главных» веток (master/develop/production/release).

Следующая стадия — staging — это набор сред для разработчиков, DevOps-инженеров и тестировщиков. Здесь объявлено несколько задач, разворачивающих приложения из веток с префиксами feature_ и infra_ в урезанных средах для быстрого тестирования новой функциональности или инфраструктурных изменений (код сборки приложения хранится в репозитории приложения).

Стадии pre-production и production доступны только для тегов. Обычно тег вешается после того, как релиз-инженеры принимают несколько merge-запросов из протестированных веток. В целом можно сказать, что мы используем GitLab Flow с тем лишь отличием, что нет автоматического развёртывания на production и потому нет отдельных веток, а используются теги.

Стадия approve — это две задачи: approve и not approve. Первая включает возможность развёртывания на production, вторая — выключает. Эти задачи существуют для того, чтобы в случае проблем на production было видно, что развёртывание происходило не просто так, а с согласия релиз-инженера. Однако суть не в лишении кого-то премии, а в том, что непосредственно развёртывание на production проводит зачастую не сам релиз-инженер, а команда DevOps. Релиз-инженер, запуская задачу approve, разрешает тем самым «нажать на кнопку» deploy to production команде DevOps. Можно сказать, что эта стадия выносит на поверхность то, что могло бы остаться в почтовой переписке или в устной форме.

Такая схема взаимодействия хорошо себя показала в работе, однако пришлось потрудиться, чтобы реализовать её. Как оказалось, GitLab CI не поддерживает из коробки некоторые нужные вещи…

Разработка .gitlab-ci.yml

Изучив документацию и различные статьи, можно быстро набросать такой вариант .gitlab-ci.yml, соответствующий описанным стадиям пайплайна:

stages:
  - build
  - testing
  - staging
  - preprod
  - approve
  - production

## build stage
build:
  stage: build
  tags: [deploy]
  script:
    - echo "Build"

## testing stage
test unit:
  stage: testing
  tags: [deploy]
  script:
    - echo "test unit"

test integration:
  stage: testing
  tags: [deploy]
  script:
    - echo "test integration"

test selenium:
  stage: testing
  tags: [deploy]
  script:
    - echo "test selenium"

## staging stage
.staging-deploy: &staging-deploy
  tags: [deploy]
  stage: staging
  when: manual
  script:
    - echo $CI_BUILD_NAME


deploy to dev-1:
  <<: *staging-deploy

deploy to dev-2:
  <<: *staging-deploy

deploy to devops-1:
  <<: *staging-deploy

deploy to devops-2:
  <<: *staging-deploy

deploy to qa-1:
  <<: *staging-deploy

deploy to qa-2:
  <<: *staging-deploy


## preprod stage
deploy to preprod:
  stage: preprod
  tags: [deploy]
  when: manual
  script:
    - echo "deploy to preprod"

## approve stage
approve:
  stage: approve
  tags: [deploy]
  when: manual
  script:
    - echo "APPROVED"

NOT approve:
  stage: approve
  tags: [deploy]
  when: manual
  script:
    - echo "NOT APPROVED"

## production stage
deploy to production:
  stage: production
  tags: [deploy]
  when: manual
  script:
    - echo "deploy to production!"

Всё довольно просто и скорее всего понятно. Для каждой задачи используются следующие директивы:

  • stage — определяет стадию, к которой относится задача;
  • script — действия, которые будут произведены, когда запустится задача;
  • when — вид задачи (manual означает, что задача будет запускаться из пайплайна вручную);
  • tags — теги, которые в свою очередь определяют, на каком раннере будет запущена задача.

Примечание: Раннер — часть GitLab CI, аналогичная другим системам CI, т.е. агент, который получает задачи от GitLab и выполняет их script.
GitLab CI для непрерывной интеграции и доставки в production. Часть 1: наш пайплайн - 4
Слайд про раннеры из презентации «Coding the Next Build» (ⓒ 2016 Niek Palm)

Кстати, заметили этот блок?

.staging-deploy: &staging-deploy
  tags: [deploy]
  stage: staging
  when: manual
  script:
    - echo $CI_BUILD_NAME

Он демонстрирует возможность формата YAML определять общие блоки и подключать их в нужное место на нужном уровне. Подробнее см. в документации.

В описании пайплайна было сказано, что стадии approve и production доступны только для тегов. В .gitlab-ci.yml это можно сделать с помощью директивы only. Она определяет ветки, для которых будет создаваться пайплайн, а с помощью ключевого слова tags можно разрешить создавать пайплайн для тегов. К сожалению, директива only есть только для задач — её нельзя указать при описании стадии.

Таким образом, задачи на стадиях build, testing, staging, pre-production, которые должны быть доступны для веток infra_, feature_ и тегов, принимают следующий вид:

test unit:
  stage: testing
  tags: [deploy]
  script:
    - echo "test unit"
  only:
    - tags
    - /^infra_.*$/
    - /^feature_.*$/

А задачи на стадиях approve и production, которые доступны только для тегов, имеют такой вид:

deploy to production:
  stage: production
  tags: [deploy]
  script:
    - echo "deploy to production!"
  only:
    - tags

В полном варианте директива only вынесена в общий блок (пример такого .gitlab-ci.yml доступен здесь).

Что дальше?

На этом создание .gitlab-ci.yml для описанного пайплайна затормаживается, т.к. GitLab CI не предоставляет директив, во-первых, для разделения задач по пользователям, а во-вторых, для описания зависимостей выполнения задач от статуса выполнения других задач. Также хотелось бы разрешить изменять .gitlab-ci.yml только отдельным пользователям.

Полная реализация задуманного стала возможной только благодаря нескольким патчам к GitLab и использованию артефактов задач. Подробнее об этом я расскажу в следующей части статьи (мы опубликуем её в среду).

Автор: diafour

Источник

Поделиться