Thank you for reading this post, don't forget to subscribe!
Шаблоны
В данном разделе напишем несколько готовых шаблонов, которые можно взять за основы при написании своего сценария.
1. Минимальный сценарий. Для небольших заданий, состоящих из пары заданий:
1 2 3 4 5 6 7 |
stages: - build TASK_NAME: stage: build script: - ./build_script.sh |
* где:
- stages — описание стадий нашего пайплайна. В данном примере, всего одна.
- TASK_NAME — имя нашей задачи.
- stage — стадия, к которой относится наше задание.
- script — набор скриптов для выполнения.
2. Стандартный цикл при сборке. Обычно, процесс CI/CD включает следующие шаги:
- Сборка пакета.
- Тестирование.
- Доставка.
- Развертывание.
Для написания такого сценария за основу можно взять шаблон:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
stages: - build - test - delivery - deploy build-job: stage: build script: - echo "Start build job" - build-script.sh test-job: stage: test script: - echo "Start test job" - test-script.sh delivery-job: stage: delivery script: - echo "Start delivery job" - delivery-script.sh deploy-job: stage: deploy script: - echo "Start deploy job" - deploy-script.sh |
Задания
В данном разделе мы рассмотрим опции, которые могут применяться при описании задания. Общий синтаксис:
1 2 3 |
<TASK_NAME>: <OPTION1>: … <OPTION2>: … |
Мы перечислим лишь часто встречаемые опции. Полный список можно найти в официальной документации.
Stage
https://docs.gitlab.com/ee/ci/yaml/#stages.
Опция указывает, к какой стадии относится задание. Например:
1 2 3 4 |
TASK_NAME: ... stage: build |
Сами же стадии описываются в общей директиве stages.
Image
https://docs.gitlab.com/ee/ci/yaml/#image.
Задаем имя образа, если наше задание выполняется в контейнере docker:
1 2 3 |
TASK_NAME: ... image: debian:11 |
Before_script
https://docs.gitlab.com/ee/ci/yaml/#before_script.
Данная опция определяет список команд, которые должны выполняться перед опцией script и после получения артефактов.
1 2 3 4 |
TASK_NAME: ... before_script: - echo "Run before_script" |
Script
https://docs.gitlab.com/ee/ci/yaml/#script.
Основная часть, где выполняются задания сценария, описана в опции script. Рассмотрим ее подробнее.
1. Описание массива команд. Мы просто перечисляем списком те команды, которые необходимо последовательно выполнить нашему сценарию в конкретной задаче:
1 2 3 4 5 |
TASK_NAME: ... script: - command1 - command2 |
2. Длинные команды, разбитые на несколько строк. Нам может потребоваться выполнить команды в виде скрипта (с операторами сравнения, например). В этом случае будет удобна многострочная запись. Ее можно указать разными способами.
Индикатор | :
1 2 3 4 5 6 |
TASK_NAME: ... script: - | command_line1 command_line2 |
* для него каждая новая строка является переходом к новой команде или части оператора. По сути, это близко к логике скрипта shell.
Индикатор > :
1 2 3 4 5 6 7 8 9 |
TASK_NAME: ... script: - > command_line1 command_line1_continue command_line2 command_line2_continue |
* данный индикатор интерпретирует новую команду после пустой строки.
After_script
https://docs.gitlab.com/ee/ci/yaml/#after_script.
Набор команд, которые запускаются после scripts, даже, при неудачном завершении последнего.
1 2 3 4 5 6 7 |
TASK_NAME: ... script: ... after_script: - command1 - command2 |
Artifacts
https://docs.gitlab.com/ee/ci/yaml/#artifacts.
Артефакты представляют из себя промежуточные сборки или файлы, которые могут передаваться от одного этапа — другому.
1. Например, так можно указать, какие файлы будут артефактами:
1 2 3 4 5 6 7 |
TASK_NAME: ... artifacts: paths: - ${PKG_NAME}.deb - ${PKG_NAME}.rpm - *.txt |
* в моем примере, в артефакты попадут все файлы, название которых заканчивается на txt, а также файлы ${PKG_NAME}.deb и ${PKG_NAME}.rpm, где ${PKG_NAME} — переменная (подробнее о переменных ниже).
В других заданиях, которые будут выполняться после можно использовать артефакты, обращаясь к ним по именам, например:
1 2 3 4 5 6 |
TASK_NAME_2: ... script: - cat *.txt - yum -y localinstall ${PKG_NAME}.rpm - apt -y install ./${PKG_NAME}.deb |
2. Также мы можем передать системные переменные, которые были нами переданы в файл:
1 2 3 4 5 6 7 8 |
TASK_NAME: ... script: - echo -e "VERSION=1.1.1" > variables.env ... artifacts: reports: dotenv: variables.env |
* в данном примере мы передадим системную переменную VERSION со значением 1.1.1 через файл variables.env.
Extends
https://docs.gitlab.com/ee/ci/yaml/#extends.
Позволяет вынести часть сценария в отдельный блок и объединить его с заданием. Чтобы это лучше понять, рассмотрим конкретный пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.my_extend: stage: build variables: USERNAME: my_user script: - extend script TASK_NAME: extends: .my_extend variables: VERSION: 123 PASSWORD: my_pwd script: - task script |
И так, в нашем задании TASK_NAME мы используем extends. В результате, задание примет такой вид:
1 2 3 4 5 6 7 8 |
TASK_NAME: stage: build variables: VERSION: 123 PASSWORD: my_pwd USERNAME: my_user script: - task script |
Что произошло:
- stage: build попало в задание из my_extend.
- произошло объединение variables, итого в задание попали VERSION, PASSWORD и USERNAME.
- script используется из задания (значения ключей не объединяются, приоритет за значением основного задания).
Environment
https://docs.gitlab.com/ee/ci/yaml/#environment.
Позволяет указать системную переменную, которая будет создана для выполнения задания.
1 2 3 4 5 |
TASK_NAME: ... environment: RSYNC_PASSWORD: rpass EDITOR: vi |
Директивы правил и ограничений
Для управления поведением выполнения задач могут использоваться директивы с правилами и условиями. Подробнее мы их рассмотрим ниже, а в данном разделе просто перечислим их.
Rules
https://docs.gitlab.com/ee/ci/yaml/#rules.
Правила, при соблюдении которых наше задание может быть запущено.
When
https://docs.gitlab.com/ee/ci/yaml/#when.
Определяет условия запуска задания, например, только ручной запуск или через определенный интервал времени.
Needs
https://docs.gitlab.com/ee/ci/yaml/#needs.
Тоже набор правил, требующий определенных условий для запуска задачи.
Правила и условия
Мы можем выполнять или пропускать задания, в зависимости от выполнения определенных условий. Для этого существует несколько полезных директив, которые мы рассмотрим в данном разделе.
Rules
Регламентирует различные правила, определенные с помощью:
- if.
- changes.
- exists.
- allow_failure.
- variables.
1. Оператор if. Позволяем проверить условие, например, если переменная равна определенному значению:
1 2 3 4 |
TASK_NAME: ... rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' |
* в данном примере коммит должен быть выполнен в бранче по умолчанию.
2. Изменения затронули определенные файлы. Проверка выполняется с помощью опции changes.
В данном примере, файл script.sql:
1 2 3 4 5 |
TASK_NAME: ... rules: - changes: - script.sql |
3. Несколько условий. Условий для начала выполнения задания может быть несколько. Рассмотрим несколько примеров.
а) При условии, что коммит выполнен в бранче по умолчанию И изменения затронули файл script.sql:
1 2 3 4 5 6 |
TASK_NAME: ... rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' changes: - script.sql |
б) При условии, что коммит выполнен в бранче по умолчанию ИЛИ изменения затронули файл script.sql
1 2 3 4 5 6 |
TASK_NAME: ... rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - changes: - script.sql |
4. Проверка на существование файла. Определяется с помощью exists:
1 2 3 4 5 |
TASK_NAME: ... rules: - exists: - script.sql |
* задание будет выполняться только в случае присутствия файла script.sql.
5. Разрешить сбой задания. Задается с помощью allow_failure:
1 2 3 4 |
TASK_NAME: ... rules: - allow_failure: true |
* в данном примере наш конвейер продолжит работу, если задание TASK_NAME будет выполнено с ошибкой.
6. Определение переменной в зависимости от условия. Для этого используются вместе if и variables:
1 2 3 4 5 6 7 8 9 |
TASK_NAME: ... rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' variables: DEPLOY_VARIABLE: "production" - if: '$CI_COMMIT_BRANCH =~ demo' variables: DEPLOY_VARIABLE: "demo" |
When
Определяет условия запуска задания. Возможные значения:
- on_success (по умолчанию) — если все задания на более ранних этапах завершились успешно или имеют allow_failure: true.
- manual — запуск вручную (в панели pipeline появится кнопка запуска).
- always — запускать всегда, независимо от предыдущих результатов.
- on_failure — только в случае сбоя, хотя бы, одного задания на более раннем этапе.
- delayed — отложить запуск задания. Контролировать срок можно с помощью директивы start_in.
- never — никогда не запускать задание.
Разберем примеры.
1. Manual:
1 2 3 |
TASK_NAME: ... when: manual |
* задание не начнет выполняться, пока мы не нажмем кнопку запуска в GitLab CI/CD.
2. Always:
1 2 3 |
TASK_NAME: ... when: always |
* задание будет выполняться всегда. Удобно, например, если нужно сформировать отчетный файл, независимо от результатов сборки.
3. On_failure:
1 2 3 |
TASK_NAME: ... on_failure: always |
* задание будет выполняться при наличии ошибки на ранних этапах. Можно использовать для отправки уведомления.
4. Delayed:
1 2 3 4 |
TASK_NAME: ... when: delayed start_in: 30 minutes |
* запуск задания будет отложен на 30 минут.
5. Never:
1 2 3 |
TASK_NAME: ... when: never |
* задание не будет выполняться.
6. Использование вместе с if:
1 2 3 4 5 |
TASK_NAME: ... rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' when: manual |
* в данном примере задание будет выполняться, если коммит прошел в основной ветке и если администратор подтвердил запуск.
Needs
Позволяет задавать условия выполнения заданий только при наличии определенного артефакта или выполненного задания. С помощью правил данного типа можно контролировать порядок выполнения задач.
Рассмотрим примеры.
1. Artifacts. Принимает значение true (по умолчанию) и false. Для запуска задания нужно, чтобы на предыдущих этапах были загружены артефакты. Запись:
1 2 3 4 |
TASK_NAME: ... needs: - artifacts: false |
… позволяет начать выполнение задания без этого.
2. Job. Позволяет начать выполнение задачи только после завершения другого задания:
1 2 3 4 |
TASK_NAME: ... needs: - job: createBuild |
* в нашем примере задача начнет выполняться не раньше завершения задачи с названием createBuild.
Дополнительные параметры и переменные
В данном разделе мы рассмотрим различные опции, которые не вошли в другие разделы, а также работу с переменными.
1. Workflow. Позволяем задать общие правила запуска для всего конвейера. Рассмотрим пример с официального сайта:
1 2 3 4 5 6 |
workflow: rules: - if: $CI_COMMIT_TITLE =~ /-draft$/ when: never - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH |
В данном примере конвейер:
- Не будет запущен, если название коммита содержит текст draft.
- Будет запущен, если пайплайн сработал после merge request.
- Будет запущен, если изменения внесены в основную ветку репозитория.
2. Значения по умолчанию. Задаются в директиве default. Опции с данными значениями будут использоваться во всех заданиях или могут быть переопределены на уровне конкретного задания.
Пример:
1 2 3 4 |
default: image: centos:7 tags: - ci-test |
* мы определили опцию с именем образа (например, образа docker) и тег (теги могут быть необходимы для запуска некоторых runner).
3. Импорт конфигурации из другого файла yml. Может быть полезным, например, для написания общей части сценария, которую мы захотим применять ко всем pipeline. Выполняется с помощью опции include:
1 2 |
include: - template: Custom/.gitlab-ci.yml |
* в данном примере мы подключим к нашему сценарию содержимое файла Custom/.gitlab-ci.yml.
4. Определение и использование переменных. Задаются с помощью директивы variables.
Можно определить глобально для всех заданий:
1 2 |
variables: PKG_VER: "1.1.1" |
Или для конкретного задания:
1 2 3 4 |
TASK_NAME: ... variables: PKG_VER: "1.1.1" |
Теперь можно использовать нашу переменную в сценарии. Для этого ставим перед ее названием знак доллара, а также стоит заключить его в фигурные скобки, например:
1 2 |
script: - echo ${PKG_VER} |