Руководство по CI/CD в GitLab для новичка
В статье разбираем, как устроена практика CI/CD, какие у нее нюансы и преимущества использования. А также расписываем пошаговый процесс использования CI/CD в GitLab и практический пример реализации.
Что такое CI/CD и зачем нужна эта практика
CI/CD (Continuous Integration/Continuous Deployment) в переводе означает «непрерывная интеграция и непрерывная доставка». Под этим понятием подразумевают практики и принципы, которые позволяют сделать тестирование автоматизированным, а новые модули сразу доставлять всем, кому нужно: DevOps-инженерам, программистам, тимлидам, пользователям и так далее.
CI/CD состоит из двух частей:
CI (Continuous Integration) — непрерывная интеграция
Это практика, согласно которой разработчики могут предлагать изменения в основной код проекта. При этом делать это могут фактически неограниченное количество раз в день. Для создания такого предложения существует отдельная сущность — MR (Merge Request, в некоторых системах вроде GitHub она же называется PR — Pull Request). Она содержит предложенное изменение и необходимый набор сопровождающих комментариев.
Другие члены команды могут провести процесс ревью кода (Code Review) — то есть посмотреть, что именно предлагается изменить в проекте и задать вопросы или принять это изменение. При этом при создании MR может выполняться запуск автоматического процесса сборки и тестирования.
С помощью этого процесса новые изменения могут проверяться на корректность синтаксиса, отсутствие логических ошибок и дополнительно проверяются человеком во время ревью кода.
Почему CI важен:
- Позволяет обнаружить проблемы на ранних стадиях — еще до слияния изменений в основную ветку проекта. В поиске багов как раз и помогает автоматическое тестирование.
- Появляется быстрая обратная связь. Если в коде обнаруживаются проблемы, разработчики почти моментально получают уведомления об этом от самого CI. Это помогает быстрее исправлять ошибки.
- Распространение знаний об устройстве проекта. Ревьюеры (те, кто проводят ревью кода) перед принятием изменения изучают его, что позволяет делиться знаниями о функционировании конкретных компонентов кодовой базы.
- Проще поддерживать стабильность кода. Изменения, которые не прошли процесс CI, просто не могут попасть в кодовую базу проекта — у автора изменения, как правило, нет технической возможности внести нестабильные и/или неработающие изменения.
CD (Continuous Deployment) — непрерывная доставка
CD дополняет практику CI за счет того, что после сборки проекта с внесенными после прохождения CI изменениями, артефакты сборки автоматически развертываются на серверы. А главная задача CD — оперативно и без перебоев доставлять обновления пользователям без необходимости включения разработчика или прерывания работоспособности сервиса.
Почему CD важен:
- Сокращается время релиза после внесения изменений. Здесь все просто: за счет автоматизации фичи доставляются пользователям быстрее.
- Уменьшает простой сервисов при обновлении программных продуктов. Релиз практически любого программного продукта требует его перезапуска, что создает время простоя и риски неработоспособности. Практики CD позволяют проверить приложение на работоспособность до того, как оно получит трафик реальных пользователей и постепенно увеличивать его долю до полного переключения на новую версию приложения.
- Увеличивается частота релизов. Это опциональный пункт и зависит от команды разработки и компании. Но глобально идея в том, что CD позволяет быстро выпускать обновления хоть на каждое внесенное изменение, фрагментируя релизы до самых маленьких фичей и фиксов.
![](../media/2024/07/shutterstock_2487440815-2.jpg)
Как устроен процесс CI/CD
Этап 1. Написание и коммит кода
Создание изменений
Прежде чем приступать к процессу CI/CD, нужно написать новый код или внести изменения в существующий. Разработчики работают в локальных ветках, где они могут безопасно вносить изменения без влияния на основную ветку проекта. Затем разработчики тестируют код — в ручном режиме или запускают уже существующие или написанные ими же тесты. После этого переходят к следующему этапу.
Коммит и пуш
После внесения изменений разработчик коммитит их в локальную ветку и отправляет в удаленный репозиторий, размещенный, в нашем примере, в GitLab — так можно сохранить свои изменения, например для продолжения работы на следующий день, не переживая за локальную копию. Затем, для запуска процесса CI и, возможно, запроса ревью кода со стороны других членов команды, нужно создать MR.
Этап 2. Запуск непрерывной интеграции (CI)
Запуск пайплайна
Каждый MR в репозитории автоматически запускает пайплайн CI, который описан в файле .gitlab-ci.yml.
Сборка кода
Первый этап пайплайна CI обычно включает сборку кода. В зависимости от технологии проекта это может быть проверка синтаксиса посредством запуска линтеров, компиляция, сборка образов контейнеров или другие действия.
Этап 3. Проведение тестирования
Здесь проводятся юнит-тесты, интеграционные тесты, которые помогают обнаружить ошибки и баги на ранних стадиях разработки.
Этап 4. Ревью кода и обратная связь
Когда тесты заканчиваются успешно, разработчик получает уведомление об успешном прохождении CI для своего изменения. Если тесты или сборка проекта завершаются с ошибкой, разработчик видит детальные данные об этой ошибке и может оперативно внести изменения.
Также на этом этапе код может посмотреть заказчик и другие участники проекта. Если все в порядке, разработчик приступает к следующему этапу. В противном случае в код вносят исправления.
Этап 5. Развертывание и запуск пайплайна CD
После того, как этапы CI успешно пройдены, изменения нужно смержить (слить) с основной веткой проекта, как правило это master или main. После чего запускается часть CD, которая автоматически развертывает изменения на тестовый или продакшн сервер.
Если присутствует этап развертывания в тестовое окружение, то там приложение может быть отдельно проверено на совместимость с остальными компонентами — например, в рамках этапа e2e тестирования в тестовой среде. После чего приложение разворачивается в продакшн-окружение, то есть доставляется конечному потребителю.
Преимущества использования практики CI/CD
1. Сокращается время релизов
Технология CI/CD помогает решать рутинные задачи проще, автоматизируя их. Благодаря этому, команды могут быстрее выпускать новые версии. А если понадобятся изменения, они так же легко и просто проходят по пайплайну внесения изменений.
В CI/CD активно используются автоматические тесты. Это позволяет находить баги на ранних стадиях. В итоге растет общее качество кода, снижается число ошибок. А сам продукт становится стабильнее.
2. Улучшается командная работа
За счет прозрачной работы CI/CD, командная коммуникация тоже становится значительно проще. Так, каждый сотрудник знает, что внедренные изменения будут проверены и корректны в работе. А значит снизится количество конфликтов и вырастет общая продуктивность команды.
3. Уменьшается человеческий фактор
Чем больше процессы автоматизированы, тем меньше вероятность человеческой ошибки. Это тоже работает на безопасность всех процессов: от разработки до развертывания.
4. Растет гибкость и масштабируемость
CI/CD позволяет легко масштабировать процессы разработки и адаптироваться к постоянно меняющимся требованиям бизнеса, внося и тестируя изменения разных масштабов от одной строчки до, фактически, бесконечности.
Инструменты для работы с практикой CI/CD
CI/CD — это технология, для использования которой есть разные инструменты. Вот несколько популярных вариантов:
- GitLab CI/CD — это комплексная система, встроенная в GitLab, которая автоматизирует процессы сборки, тестирования и развертывания программного обеспечения. GitLab CI/CD управляет конфигурациями через YAML-файлы, находящимися в репозитории проекта. Инструмент позволяет интегрироваться с кластерами Kubernetes. А еще поддерживает применение образов контейнеров для настройки окружения — это обеспечивает высокую гибкость и позволяет многократно использовать код.
- Microsoft Azure DevOps — этот инструмент подходит не только для CI/CD, он полностью помогает процессу разработки. Команды могут ставить в нем задачи, совместно работать над кодом и развертывать приложения. Чтобы автоматизировать часть этапов разработки применяют Azure Pipelines.
- Jenkins — один из старейших инструментов CI/CD, опенсорс приложение, предназначенное специально для внедрения CI/CD в процесс разработки. Особенность в том, что Jenkins нужно отдельно устанавливать и настраивать. Из плюсов — инструмент поддерживает больше тысячи плагинов, обладает максимально гибкой конфигурацией и огромным сообществом, что позволяет сделать настройку более гибкой, а также получить помощь при возникновении проблем или вопросов.
В нашем примере мы будем разбирать использование CI/CD в GitLab, потому что это один из наиболее популярных, масштабируемых и гибких инструментов используемых в компаниях по всему миру. Он позволяет получить в self-hosted варианте систему, по функциональности достигающую уровня коммерческих сервисов совершенно бесплатно в GitLab Community Edition.
Основы синтаксиса .gitlab-ci.yml
Файлы .gitlab-ci.yml — центральный элемент GitLab CI/CD. С помощью него описываются все этапы сборки, тестирования и развертывания проекта. Он размещается в корневой папке проекта и написан на языке разметки YAML.
Состав файла конфигурации
Файл .gitlab-ci.yml состоит из нескольких секций, которые определяют различные аспекты пайплайна). У каждый секции файла своя функция, выполняющаяся во время CI/CD:
Stages
Этапы определяют порядок выполнения различных групп задач и делают так, чтобы они выполнялись последовательно. А еще этапы помогают грамотно организовать задачи (jobs) в группы: например, сборка, тестирование и развертывание.
Пример:
1 2 3 4 |
stages: - build - test - deploy |
Job
Это часть пайплайна, которая дает инструкции к выполнению задач. Как мы уже говорили, задачи распределены по этапам. Если у двум задачам назначить этап один, задачи будут запускаться параллельно, если нет обратных условий. Например, задача на этапе сборки может компилировать код, а задача на этапе тестирования — запускать тесты. В приведенном примере описаны три задачи (Job): build_job, test_job, deploy_job с соответствующими, назначенными им этапами.
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
build_job: stage: build script: - echo "Сборка кода..." test_job: stage: test script: - echo "Запуск тестов..." deploy_job: stage: deploy script: - echo "Развертывание приложения..." |
Script
Определяет набор команд, выполняющихся в одной задаче. Можно назвать эту часть конфигурации одной из самых важных — именно тут прописываются все команды, которые должны быть выполнены в конкретной задаче.
Пример:
1 2 3 4 5 6 7 |
build: image: ubuntu:24.04 stage: build tags: - cloud-runner script: - docker build -t "image:tag" -t "image:latest" --push. |
Before_script и after_script
Эти ключи определяют команды, которые выполняются до (before_script) и после (after_script) выполнения всех задач в пайплайне. Например, перед выполнением задач можно войти в реестр Docker, а после — выйти из него.
Пример:
1 2 3 4 |
before_script: - docker login -u <username> -p ${password} index.docker.io after_script: - docker logout index.docker.io |
Variables
С помощью этого элемента устанавливаются переменные окружения. Их можно использовать на каждом этапе пайплайна. За счет переменных можно устанавливать параметры для задач — так становится проще настраивать и управлять конфигурацией. Из самого простого: можно назначить переменную для URL базы данных, а затем использовать ее и в других задачах.
Пример:
1 2 |
variables: DATABASE_URL: "postgres://user:password@hostname:5432/dbname" |
Include
Дает возможность включить внешние YAML-файлы, чтобы использовать конфигурации по нескольку раз. Это помогает управлять крупными пайплайнами. Например, можно использовать одну конфигурацию в нескольких проектах или разделить крупный файл конфигурации на несколько частей и переиспользовать их.
Пример:
1 2 3 4 5 |
include: - project: 'my-group/my-project' ref: master file: '/templates/.template.yml' - local: '/ci/common.yml' |
Artifacts
Элемент GitLab Artifacts — файлы, которые создаются во время выполнения задачи. Они сохраняются, а затем их можно использовать повторно в других задачах. Так, можно сохранить результаты тестирования или передать скомпилированные файлы между задачами.
Пример:
1 2 3 4 |
artifacts: paths: - build/ expire_in: 1 week |
Cache
Дает возможность сохранить в кэше зависимости или любые иные сложно воспроизводимые данные, созданные во время выполнения задач. С помощью этой функции можно ускорить выполнения пайплайнов за счет отсутствия необходимости выполнять долгие операции каждый раз.
Пример:
1 2 3 |
cache: paths: - project-venv |
Image
Указывает образ контейнера, который будет использоваться для выполнения задачи. Это заранее настроенное окружение с установленными зависимостями. Например, можно использовать образ с установленной версией Ruby для задач, связанных с этим языком программирования.
Пример:
1 |
image: ruby:2.7 |
Services
Позволяют запускать дополнительные контейнеры, которые нужны для выполнения задач, например, базы данных. Элемент помогает в тестировании, когда требуется наличие внешнего работающего сервиса.
Пример:
1 2 |
services: - mysql:9 |
Only и except
Эти ключи выделяют условия для выполнения или пропуска задач. Например, задачи могут выполняться только на определённых ветках репозитория или, наоборот, пропускаться для определенных тегов.
Пример:
1 2 3 4 5 |
only: - master - develop except: - v.* |
Rules
Правила предлагают более гибкие условия для выполнения задач по сравнению с only и except. Например, можно задать условия выполнения задач в зависимости от имени ветки или результата предыдущих задач.
Пример:
1 2 3 4 |
rules: - if: $CI_COMMIT_BRANCH exists: - Dockerfile |
Tags
Теги используются для определения, какие GitLab Runner'ы (агенты, выполняющие задачи) будут запускать задачи. Это помогает распределять задачи по различным агентам в зависимости от их возможностей.
Пример:
1 2 3 |
tags: - docker - linux |
Environment
Окружение управляет развертыванием задач в определенные среды, например, в тестовую или продакшн. Это помогает автоматически разворачивать и тестировать код в различных условиях.
Пример:
1 2 3 |
environment: name: production url: https://prod.example.com |
Interruptible
Этот ключ позволяет прерывать задачи, если запускается новая сборка. Это полезно для экономии ресурсов, когда более старая сборка уже не актуальна.
1 2 3 4 5 |
build: stage: build script: - echo "This build can be canceled." interruptible: true |
Parallel
Параллельность позволяет запускать несколько экземпляров задачи одновременно. Например, можно параллельно запускать тесты с различными параметрами, чтобы ускорить процесс.
Пример:
1 2 3 |
parallel: matrix: - TEST_SUITE: ["unit", "integration"] |
Итак, мы разобрали главные составляющие файла .gitlab-ci.yml. На самом деле, их гораздо больше, а сам GitLab CI/CD дает множество опций для настройки и создания многоуровневых пайплайнов. Постоянное изучение CI/CD поможет углубить знания и использовать лучшие практики.
Пошаговый процесс настройки CI/CD в GitLab
Перед тем, как приступить к разбору практического примера, нам нужно настроить CI/CD в GitLab. В нашем блоге уже есть подробная инструкция по установке CI/CD на облачный сервер. Рекомендуем начать с нее.
Практический пример
В этом блоке приведем пример YAML-конфигурации для GitLab CI. Как выше упоминалось, CI/CD-пайплайны в GitLab описываются с помощью YAML-файлов, именованных особым образом и находящихся в определенном месте.
Для создания первого пайплайна в уже существующем проекте необходимо создать файл “.gitlab-ci.yml” в корне проекта, в нем будет описано что запускать и как запускать. Например:
1 2 3 4 5 6 7 8 9 10 11 |
build: image: ubuntu:24.04 stage: build tags: - cloud-runner before_script: - echo "Before run" script: - echo "Run" after_script: - echo "After run" |
В этом примере мы в базовом образе ubuntu:24.04 выполняем три скрипта:
- script — основной скрипт сборки нашего приложения
- before_script — скрипт, запускаемый перед основным, например, для выполнения служебных функций вроде аутентификации в container registry.
- after_script — скрипт, запускаемый после основного, например, для того, чтобы подчистить за собой все лишнее.
- tags — теги раннера, на котором запускается пайплайн.
- stage — название стадии сборки, используется для более сложных пайплайнов, чтобы задать очередность выполнения нескольких стадий сборки.
Попробуем пример чуть сложнее: протестируем свой проект на Python, с тестами, которые бы запускались только в случае коммита в ветку и при наличии файла requirements.txt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
python-test: image: python:3.12 stage: test tags: - linux - docker before_script: - pip install -r requirements.txt script: - pytest -vvv rules: - if: $CI_COMMIT_BRANCH exists: - requirements.txt |
Для работы вышеописанного примера в репозитории должен быть файл requirements.txt с добавленным pytest.
Резюме
GitLab предоставляет удобные и гибкие инструменты для реализации CI/CD-пайплайнов практически любой сложности. При этом он упрощает разработку самих пайплайнов за счет хранения конфигурации CI/CD вместе с кодом в одном Git-репозитории. В свою очередь, сама практика CI/CD позволяет увеличить производительность команд разработки и эксплуатации за счет автоматизации процессов ревью, тестирования и развертывания приложений. Это позволяет бизнесу быть гибким и оперативно вносить изменения в свои программные продукты.
Ксения Иванчикова