pipeline

Первый пайплайн в GitLab CI

На прошлом шаге пайплайн был псевдокодом для понимания идеи. Теперь соберем настоящий и разберем, как все устроено в GitLab. Почему именно GitLab: код у вас уже лежит там (модуль про Git), CI встроен в ту же платформу, и чтобы все заработало, нужно добавить в репозиторий ровно один файл.

Один файл запускает все

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

Файл в формате YAML, том же, что вы видели у Docker Compose. А значит, действует и то же предупреждение: YAML чувствителен к отступам, отступы только пробелами, табы запрещены. Сбитый отступ ломает весь файл.

Job, stage и pipeline

Вся конструкция стоит на трех понятиях.

Джоба (job) – это единица работы, набор команд, которые надо выполнить. У каждой джобы есть script, список команд, ровно таких же, что вы бы набирали бы в терминале вручную. Это самый маленький кирпичик.

Этап (stage): в него джобы группируются по смыслу, знакомому по анатомии пайплайна: lint, test, build, deploy. Этапы идут строго по очереди, а вот джобы внутри одного этапа выполняются параллельно.

Пайплайн (pipeline) – это весь прогон целиком, все этапы со всеми джобами для одного пуша.

Логика та же, что у конвейера-фильтра с прошлого шага: не прошел этап, пайплайн встал, и дальше код не едет.

Кто на самом деле выполняет команды

Сам GitLab команды не запускает. Этим занимается отдельная программа, GitLab Runner. Раннер берет джобу, поднимает чистый контейнер из указанного Docker-образа и выполняет script внутри него. Здесь напрямую всплывает модуль про Docker: образ для джобы задается полем image, например python:3.12, и команды выполняются именно в нем.

На GitLab.com раннеры уже предоставлены, так называемые shared runners, так что для старта свой ставить не нужно. Компании часто разворачивают собственные раннеры на своих серверах, но логика та же.

Факт. Каждая джоба запускается в свежем контейнере и после себя его выбрасывает. Это значит, что пайплайн всегда стартует с чистого, известного состояния.


Настоящий минимальный пайплайн

Соберем рабочий файл для Python-приложения: прогнать тесты, потом собрать образ.

stages:
  - test
  - build
 
run-tests:
  stage: test
  image: python:3.12
  script:
    - pip install -r requirements.txt
    - pytest
 
build-image:
  stage: build
  image: docker:latest
  script:
    - docker build -t myapp .

Разберем по частям. Сверху stages задает этапы и их порядок: сначала test, затем build. Дальше идут две джобы. run-tests отнесена к этапу test (stage: test), выполняется в контейнере python:3.12 и в script ставит зависимости и запускает pytest. build-image относится к этапу build и стартует только после того, как тесты прошли; внутри она собирает Docker-образ командой из модуля про Docker. Имена джоб (run-tests, build-image) вы придумываете сами, они появятся в интерфейсе GitLab.

Что вы увидите после пуша

Запушили файл, GitLab прочитал его, создал пайплайн и раздал джобы раннеру. В интерфейсе пайплайн рисуется наглядно: этапы слева направо, джобы внутри, и у каждой кружок-статус. Прошла, зеленая галочка, та самая с первого шага. Упала, красный крест, и пайплайн останавливается на этом месте. Клик по джобе открывает ее лог: видно каждую команду из `script` и ее вывод, поэтому, когда что-то падает, причину ищут прямо там.

Несколько слов, которые встретите сразу

Базовых stages, stage, image и script хватает для первого пайплайна, но рядом почти всегда стоят еще несколько ключевых слов.

Ключевое словоЧто задает
before_scriptкоманды перед каждым script – общая подготовка
variablesпеременные, доступные джобам (адреса, имена, настройки)
rules / onlyкогда запускать джобу, например деплой – только в ветке main
artifactsфайлы, которые джоба сохраняет и передает дальше по пайплайну
tagsкакой раннер возьмет джобу

Особенно пригодятся два из них. artifacts, это и есть тот артефакт из «анатомии»: собранное на этапе build передается дальше, на деплой, или его можно скачать из интерфейса. А rules решают частую задачу: тесты гонять на каждой ветке, а выкатку на прод запускать только при пуше в main, чтобы случайная ветка ничего не задеплоила.

Причем здесь DevOps

Этот один файл в репозитории и есть автоматизированный процесс доставки из всего модуля, только теперь настоящий, а не на словах. Дальше он растет: добавляются этапы проверки безопасности, выкатка на staging, ручное подтверждение, деплой на прод по частям. Но каркас остается прежним: этапы, джобы, script, раннер. Настройка и развитие таких пайплайнов, одна из главных повседневных задач девопса, и со следующего задания вы начнете собирать их руками.

Факт. Раньше CI был отдельным инструментом, который подключали к репозиторию сбоку. В 2015 году GitLab встроил CI прямо в себя (версия 8.0), и подход: код и пайплайны в одном месте, в одном файле рядом с кодом, стал нормой. Сегодня по этому же принципу работает и GitHub Actions.

Словарик

ТерминЧто означает
.gitlab-ci.ymlФайл в корне репозитория, описывающий пайплайн
Джоба (job)Единица работы со списком команд script
Этап (stage)Группа джоб; этапы идут по очереди, джобы в этапе – параллельно
Пайплайн (pipeline)Полный прогон всех этапов для одного пуша
GitLab RunnerПрограмма, которая выполняет джобы, обычно в Docker-контейнере
imageDocker-образ, внутри которого выполняется джоба
artifactsФайлы, которые джоба передает дальше по пайплайну