
Ходит легенда, что однажды разработчики GitLab закупились шапками, сделанными из переработанных крышечек от бутылок. И их настолько вдохновила идея повторного использования, что они решили добавить такую возможность и в свой продукт. Подкрепив это всё стандартизацией CI, они представили комьюнити новый механизм — GitLab CI/CD components.
В этой статье я хочу рассказать Хабру, для чего вообще нужны компоненты, как ими пользоваться и где использовать.
Советую перед прочтением ознакомиться со статьёй по важным механизмам GitLab.
Что же это за механизм?
CI/CD components — переиспользуемые блоки конфигурации пайплайна, оформленные как версионируемые модули. Появились с 16-й версии GitLab. По сути это просто шаблоны, которые с помощью директивы inlude
подключаются в CI. Однако, в отличие от обычных шаблонов, они публикуются в отдельный каталог, благодаря чему доступны за пределами проекта, в котором реализованы, и мы можем использовать общий шаблон для нескольких проектов.
При использовании self-managed версии мы сразу забираем общие шаблоны, а также имеем возможность добавлять свои, что особенно актуально для решения проблемы дублирования кода.
Каждый шаблон — yaml-файл, содержащий определённую конфигурацию. Существует несколько паттернов их использования:
Просто добавляем директиву
include
и наслаждаемся результатом работы готового пайплайна.После включения через
include
используемextends
для использования каких-то шаблонных задач (обычно это скрытые задачи, начинающиеся с точки. Пример:.deploy-ansible
). Подробнее об этом далее.
Как этим пользоваться?
Теперь давайте подробнее рассмотрим, как можно использовать компоненты.
Подключение компонента
Основной и самый популярный способ — это директива include
.
Шаблон использования:
---
include:
- component: <FQDN>/<namespace>/<project>/<component-name>@<version>
inputs:
<param1>: <value1>
<param2>: <value2>
Пример использования:
# Пример использования встроенного компонента GiLab - Autodevops
---
include:
- component: gitlab.com/components/autodevops/build@2.11.0
inputs:
stage: build
# Пример использования своего компонента
---
include:
- component: $CI_SERVER_FQDN/my-org/deploy-components/java@1.0.0
inputs:
stage: build
version: 21
Разберём на примере нашего компонента: здесь переменная $CI_SERVER_FQDN
— домен, используемый для GitLab. Далее путь до самого проекта my-org/deploy-components/
, потом идёт имя шаблона и версия компонента javа@1.0.0
.
.gitlab-ci.yml # CI, например, для тестирования компонента
README.md # документация по эксплуатации
templates/ # основная директория с шаблонами
├── template1.yml
└── template2.yml
Гибкая настройка при использовании компонента
Важное преимущество шаблонов — возможность переопределять отдельные части при помощи директивы extends
. Давайте быстро вспомним, в чём суть обратного глубокого слияния, используемого в реализации extends
: задача дополняет базовую, при конфликте новых ключей с ключами шаблона берутся новые значения. Рассмотрим пример компонента, содержащего скрытую задачу .test
, которая требует определённых переменных, тогда для её использования мы напишем свою задачу, унаследованную от .test
:
test-job:
extends: .tests
variables:
SOME_FLAG: "true"
Это частая практика для компонентов: использовать скрытые задачи, чтобы далее дополнять их определёнными переменными или настройками, при этом сохранив основную логику.
Структура компонента
Структура CI/CD компонента в GitLab основана на yaml-файлах — шаблонах. Чтобы мы могли версионировать и делиться компонентом между проектами, мы используем отдельный проект, который также можно опубликовать в CI/CD Catalog для общего использования.
Структура проекта
Основная структура проекта выглядит примерно так:
.gitlab-ci.yml # CI например для тестирования компонента
README.md # документация по эксплуатации
templates/ # основная директория с шаблонами
├── template1.yml
└── template2.yml
templates/
: Основная директория для компонента. Она содержит все необходимые шаблоны.README.MD
: Обязательный файл с описанием компонента, примерами использования, доступными inputs (входными параметрами) и инструкциями..gitlab-ci.yml
: Рекомендую добавить CI для самого компонента. Полезно для автоматизации тестирования и версионирования.
Структура шаблонов компонента
Структура yaml-конфига для компонента делится на две части, разделённые ---
:
spec:: Метаданные компонента, включая входные параметры (inputs). Здесь мы определяем, что именно должен на вход получать наш компонент для корректной работы.
Основная конфигурация: Стандартный CI-конфиг, который использует inputs для гибкой настройки.
Давайте поговорим немного о самих inputs — параметрах, которые мы задаём, когда подключаем компонент. Именно они обеспечивают гибкость. Параметры определяются в spec.input
и содержат следующие поля:
-
type:
string (по умолчанию);
boolean;
number;
array.
default: Значение по умолчанию.
description: Описание (отображается в CI/CD Catalog).
options: Опционально, список допустимых значений. Полезно, когда мы хотим ограничить возможные варианты значений.
Чтобы подставить inputs в конфиг, используется следующий синтаксис: $[[ inputs.name ]]
.
Пример inputs:
spec:
inputs:
stage:
type: string
default: test
description: "Этап пайплайна, на котором запускаем job"
enable_cache:
type: boolean
default: false
description: "Включить кэширование зависимостей"
versions:
type: array
default: ["1.0", "2.0"]
description: "Массив версий для тестирования"
Пример компонента:
spec:
inputs:
message:
type: string
default: "Hello, World!"
description: "Сообщение для вывода"
stage:
type: string
default: test
description: "Этап пайплайна"
---
echo-job:
stage: $[[ inputs.stage ]] # Подставляем inputs.stage
script:
- echo "$[[ inputs.message ]]" # Подставляем inputs.message
Однако есть ещё одна практика для передачи значений в компонент — variables
внутри самих задач. Давайте посмотрим на пример компонента:
spec:
inputs:
message:
type: string
default: "Hello, World!"
description: "Сообщение для вывода"
stage:
type: string
default: test
description: "Этап пайплайна"
---
.echo-job: # Скрытая job
stage: $[[ inputs.stage ]] # Подставляем inputs.stage
variables: # Определение variables
GREETING_PREFIX: "Output:" # Определяем variable
MESSAGE_TEXT: "$[[ ` ]]" # Variable зависит от input
script:
- echo "$GREETING_PREFIX $MESSAGE_TEXT" # Использование variables в скрипте
И его использование:
include:
- component: gitlab.example.com/my-org/echo-component@1.0.0
inputs:
message: "I'm absolute!"
stage: build
my-echo:
extends: .echo-job # Наследует скрытую job из компонента, включая variables и script
variables: # Переопределение variables
GREETING_PREFIX: "New Prefix:"
rules: # Добавляем rules
- if: '$CI_COMMIT_BRANCH == "main"'
Здесь мы использовали переменную, определённую в variables. Также хочется обратить внимание на то, что inputs.message
мы вынесли в переменные job. Это хорошая практика, которая делает визуально код более читаемым.
У такого варианта определения переменных есть свои плюсы и минусы:
Гибкость: таким образом мы получаем более гибкую настройку конкретных job, так как задаём переменные более локально относительно inputs.
Валидация: inputs позволяет задавать варианты значений и типы переменных, что повышает надёжность. variables такой функциональностью не обладают.
Сложность и читаемость: inputs более понятны для конечного пользователя компонента, чем variables и скрытые job. Подобные решения нужно подробно пояснять в документации.
Рекомендации по использованию компонентов
Не бойтесь использовать компоненты, ограничения на
include
достаточно большие, чтобы вы могли включить столько компонентов, сколько потребуется.
Пример: проект на Java будет включать компоненты по сборке, тестированию, деплою и анализаторы (например, SAST).extends
лучше, чем копирование кода. Вынесите общую логику в компонент и дополняйте уже с помощью директивы.Используйте
rules
для директивыinclude
, когда есть шаблоны, которые не должны выполняться всегда.Перед использованием обращайтесь к документации компонента. Там вы найдёте доступные переменные, область их определения (
inputs
или черезvariables
иextends
), а также возможные способы применения и примеры.
Рекомендации по созданию компонентов:
Используйте уникальные имена для задач, потому что при включении шаблона в конфигурации он мерджится с ней. Одинаковые имена приведут к конфликту и некорректному поведению. Также при необходимости можно преднамеренно переопределять задачи из шаблона, используя одинаковые названия.
Не злоупотребляйте с вложенностью зависимостей. Компоненты могут сами включать другие компоненты, но это может усложнить поведение. Советую использовать их в меру и указывать статические версии (не
@main
).Документируйте в
README.MD
. Опишите логику, переменные и примеры использования. Это поможет вашим коллегам и вам самим в будущем.Версионирование и релизы обеспечат более стабильную работу компонента. Статические версии ведут себя более предсказуемо, чем
latest
.Тестирование самого компонента в его CI — отличная практика, особенно если вы используете автоматизацию для релизов.
Чуть-чуть выводов
GitLab CI/CD components — мощный инструмент для быстрого создания пайплайнов из готовых шаблонов. Придерживайтесь минимально необходимого переопределения, гибкой настройки через переменные и контроля версий, и вы получите воспроизводимый и легко поддерживаемый CI.
Также советую ознакомиться с основными общедоступными компонентами GitLab. Они доступны по ссылке.
© 2025 ООО «МТ ФИНАНС»
Комментарии (4)
Andrey_Solomatin
21.07.2025 15:24Было бы неплохо сравнить с другими сервисами. Пользовался таким на GitHub несколько лет назад.
kenomimi
В общем случае не надо это делать, просто не надо. Экономия на сотне строчек выливается потом в полную нечитаемость конфигов ci/cd, невозможность их оперативной правки, и разрастанию костыльной базы "ну тут не можем опцию сборки добавить, пайп стандартный править нельзя, пропиши в Makefile ручками и потом не забудь при мерже". Я молчу о том, что чтобы понять что тут происходит, надо открыть десяток файлов с инклудами, страничку с переменными, и мержить это поделие сумрачного гения в уме... Не нужна дедупликация на таких крохотных обьемах кода. А если у вас ci\cd в одной репе в пару десятков тысяч строк - вы что-то делаете не так.
Да, есть кейсы, в которых инклуды полезны, например типовой пуш артефакта, но это именно что отдельные случаи, каждый из которых надо смотреть под лупой, прежде чем выносить в компонент.
m1skam
Решение о применении GitLab Components зависит от контекста. В небольших командах с парой проектов и простыми пайплайнами избыточная абстракция может создать больше проблем, чем решить, это правда. Но мой опыт показывает, что типовые задачи встречаются в большинстве проектов, и их стандартизация приносит пользу. Что касается читаемости - имхо ключевую роль тут играет качество документации и именования. Хорошо спроектированные компоненты с понятными интерфейсами могут наоборот упростить понимание пайплайна, скрыв сложную логику за простым API.
Компоненты - это инструмент, и как и любой инструмент, его нужно применять осознанно, а не ради самого инструмента.
Andrey_Solomatin
Переиспользование через библиотеку это палка о двух концах. И те кто топит за и те кто против неправы в абстрактном контексте.