О GitLab
СкопированоGitLab — популярный веб-сервис для совместной разработки и поддержки программного обеспечения. Вы можете работать с Git-репозиториями, управлять задачами, обсуждать правки с вашей командой, писать wiki-документацию, оценивать качество, выпускать релизы и даже мониторить работающие программы — и всё это в одном месте.
Кратко
СкопированоGitLab CI — инструмент, встроенный в GitLab для автоматизации рутинных задач, возникающих в процессе разработки программного обеспечения. Спектр таких задач огромен и отличается от проекта к проекту, но основные — это тестирование, статический анализ, проверка стиля написания кода и деплой (выпуск) приложения. GitLab CI — конкурент другого популярного инструмента, GitHub Actions. Эти два сервиса во многом похожи, но есть некоторые отличия.
Пример
СкопированоДопустим, мы договорились в команде об особых правилах оформления кода при помощи EditorConfig, установили его как дев-зависимость и сделали его доступным с помощью команды npm run editorconfig. Можно запускать проверку каждый раз перед коммитом, но всегда будут ситуации, когда это забудут сделать, и код, оформленный неправильно, попадёт в репозиторий. Здесь приходит на помощь GitLab CI/CD — достаточно создать в корне проекта файл .gitlab-ci.yml со следующим содержанием:
EditorConfig: image: node:lts script: - npm ci - npm run editorconfig
EditorConfig:
image: node:lts
script:
- npm ci
- npm run editorconfig
И теперь каждый раз, когда в репозиторий попадает новый код, он будет проверяться на соответствие правилам, а ошибки будут видны в интерфейсе GitLab.
Как пользоваться
СкопированоОсновные понятия
СкопированоОсновной сущностью в GitLab CI/CD является пайплайн (pipeline) — конвейер, который может состоять из:
- джобов (jobs), описывающих что нужно выполнить;
- этапов (stages), указывающих когда или в какой последовательности нужно выполнить джобы.
Джобы в одном этапе обычно выполняются параллельно. Если все джобы завершились успешно, выполнение переходит к следующему этапу и так далее. Если любой из джобов завершился ошибкой, то выполнение останавливается, и весь пайплайн (обычно) считается проваленным.
Для передачи результатов сборки (бинарных файлов, логов, конфигураций и т. д.) между джобами используются артефакты. Артефакт — общий ресурс пайплайна, хранящийся отдельно и передающийся между этапами сборки.
Создаём .gitlab-ci.yml
СкопированоGitLab CI полностью конфигурируется с помощью одного файла в формате YAML, который нужно создать в корне проекта — .gitlab-ci.yml.
Джобы часто могут иметь одинаковые свойства, например, образ среды, в которой выполняются действия, предварительные команды и т. д. Чтобы не повторять их каждый раз, нужно объявить их в секции default. Если какому-то джобу нужны другие параметры, можно указать их внутри этого джоба, и они перезапишут глобальные параметры.
В первую очередь нужно указать Docker-образ (подробнее в статье «Что такое Docker»), в котором будут выполняться джобы. В большинстве случаев нам подойдёт официальный образ Node.js node — это означает, что наши команды будут выполняться внутри операционной системы Linux с установленными Node.js, npm и даже Yarn. Про буквы lts можно почитать в разделе про версионирование Node.js.
default: image: node:lts
default:
image: node:lts
Задаём подготовительные команды
СкопированоПри работе с CI/CD во фронтенд-проектах чаще всего перед выполнением основного действия необходимо установить зависимости. Для этого мы можем указать их в секции before — эти команды будут выполняться в каждом джобе перед основным действием.
default: image: node:lts before_script: - npm -v - npm install
default:
image: node:lts
before_script:
- npm -v
- npm install
Указываем этапы
СкопированоПредположим, что мы хотим запускать сначала проверку кодовой базы с помощью EditorConfig и Stylelint, а потом, если они обе завершатся успешно, запустить тесты. В этом примере можно выделить два этапа: стиль кода и тесты. Определить этапы можно при помощи ключевого слова stages:
stages: - Стиль кода - Тесты
stages:
- Стиль кода
- Тесты
Описываем джобы и задаём команду
СкопированоТеперь укажем все три джоба. Для этого мы вначале указываем название джоба, указываем его этап при помощи ключевого слова stage и передаём список команд в script. В нашем примере каждый джоб будет запускать по одному npm-скрипту.
default: image: node:lts before_script: - npm -v - npm cistages: - Стиль кода - ТестыEditorConfig: stage: Стиль кода script: - npm run editorconfigStylelint: stage: Стиль кода script: - npm run stylelintАвтотесты: stage: Тесты script: - npm run test
default:
image: node:lts
before_script:
- npm -v
- npm ci
stages:
- Стиль кода
- Тесты
EditorConfig:
stage: Стиль кода
script:
- npm run editorconfig
Stylelint:
stage: Стиль кода
script:
- npm run stylelint
Автотесты:
stage: Тесты
script:
- npm run test
А вот схематичное представление конфигурации выше:

Продвинутое использование
СкопированоЗапуск вручную
СкопированоЕсли мы хотим запускать определённый джоб вручную, то нужно добавить when:
job: script: npm run deploy when: manual
job:
script: npm run deploy
when: manual
Продолжение при провале
СкопированоПо умолчанию при провале любого джоба весь пайплайн отмечается как проваленный, и оставшиеся джобы не выполнятся. Однако бывают ситуации, когда этого поведения хочется избежать. Например, мы добавили джоб с тестами в только что появившейся версии Node.js и просто хотим видеть проблемы, которые потенциально нужно исправить в будущем. Здесь придёт на помощь allow:
job: image: node:latest script: npm run test allow_failure: true
job:
image: node:latest
script: npm run test
allow_failure: true
Выполнение джобов по условию
СкопированоGitLab даёт доступ к большому количеству переменных окружения с полезной информацией. Например, $ содержит текущую ветку, $ — короткий хеш коммита, $ — источник вызова текущего пайплайна и так далее. С их помощью мы можем запускать определённые джобы при соблюдении заданных условий. Для этого нужно объявить одну или несколько секций rules.
Вот такой джоб будет выполняться только для коммитов в ветку main:
job: script: npm run deploy-to-production rules: - if: '$CI_COMMIT_BRANCH == "main"'
job:
script: npm run deploy-to-production
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
Запуск по расписанию
СкопированоВ отличие от GitHub Actions, в GitLab CI/CD запуск пайплайнов по расписанию настраивается только в веб-интерфейсе. Для этого нужно открыть страницу репозитория и выбрать CI/CD → Schedules. Перед нами откроется список уже существующих правил и кнопка добавления нового. В форме добавления можно указать название правила, выбрать интервал из списка или указать свой в синтаксисе Cron. Последним важным полем является ветка — при срабатывании правила пайплайн запустится, как будто был запушен код в этой ветке. Отличие в том, что переменная $ будет содержать значение schedule.
Серия джобов
СкопированоЕщё одна типичная задача — прогнать тесты в разных версиях Node.js. Можно для каждой версии создать джоб вручную, а можно указать список переменных:
Unit Tests: script: node -v image: ${NODE_VERSION} parallel: matrix: - NODE_VERSION: ["node:14", "node:16", "node:17"]
Unit Tests:
script: node -v
image: ${NODE_VERSION}
parallel:
matrix:
- NODE_VERSION: ["node:14", "node:16", "node:17"]
В примере выше мы объявили список NODE из трёх элементов. GitLab создаст три джоба с именами: «Unit Tests [node:14]», «Unit Tests [node:16]» и «Unit Tests [node:17]», а потом в каждом джобе заменит все места использования переменной NODE. Поэтому image в каждом джобе будет разный.
Работа с подмодулями Git
СкопированоЕсли в вашем репозитории есть подмодули, GitLab автоматически попробует склонировать их перед сборкой. Для управления этой стратегией существует переменная GIT. По умолчанию её значение recursive, что означает рекурсивное клонирование всех вложенных подмодулей. Если вы хотите клонировать только «верхний» уровень подмодулей, установите значение normal для этой переменной. Если не хотите клонировать подмодули вовсе, используйте none.
variables: GIT_SUBMODULE_STRATEGY: recursive
variables:
GIT_SUBMODULE_STRATEGY: recursive
Подмодули на своём GitLab-сервере
СкопированоЕсли используете GitLab, установленный на вашем сервере, а подмодули находятся в его приватных репозиториях, нужно настроить доступ к ним.
Пример: вы создаёте файл .gitlab в репозитории на локальном GitLab. Пусть его адрес будет https. В этом репозитории файл подмодуля выглядит так:
[submodule "module"] path = module url = https://my_git.ru/group/module.git
[submodule "module"]
path = module
url = https://my_git.ru/group/module.git
Настроим доступ в репозитории group:
- Перейдите на страницу репозитория
group./ module - Зайдите в раздел «Настройки» (Settings) → «CI/CD».
- Раскройте раздел «Разрешения токена задания CI/CD» (Job token permissions).
- При помощи кнопки «Добавить» (Add) добавьте ваш основной репозиторий
myв список. Для этого введите путь до репозитория:_ cool _ repo user(без части/ my _ cool _ repo https).: / / my _ git . ru
В этом разделе можно указывать целые группы репозиторием или разрешить доступ для всех репозиториев на сервере.
Если в файле подмодулей указана ссылка для скачивания по SSH, например:
url = git@my_git.ru/group/module.git
url = git@my_git.ru/group/module.git
то вы можете принудительно указать Gitlab клонировать по https. Для этого установите ппеременную в вашем .gitlab:
variables: GIT_SUBMODULE_FORCE_HTTPS: "true"
variables:
GIT_SUBMODULE_FORCE_HTTPS: "true"
Теперь ссылка при клонировании на лету поменяется на https, при этом файл .gitmodules не изменится. Когда эта функция включена, Gitlab будет использовать токен джобы для клонирования. В этом случае использует разрешения пользователя, запустившего здание, а учетных данных SSH требоваться не будут.
Артефакты
СкопированоДля добавления файла к артефактам используют следующий синтаксис .gitlab:
job: stage: build artifacts: name: "job1-artifacts-file" paths: - ${CI_PROJECT_DIR}/build/my_app
job:
stage: build
artifacts:
name: "job1-artifacts-file"
paths:
- ${CI_PROJECT_DIR}/build/my_app
Можно использовать шаблоны поиска (wildcard):
artifacts: paths: - ${CI_PROJECT_DIR}/build-*/*.log
artifacts:
paths:
- ${CI_PROJECT_DIR}/build-*/*.log
Все артефакты можно посмотреть в разделе «Сборка» (Build) → «Артефакты» (Artifacts). Время жизни артефактов ограничено (по умолчанию 14 дней), поэтому не используйте этот раздел для долговременного хранения сборок. Для длительного хранения лучше использовать реестр пакетов.
Публикация в реестре пакетов
СкопированоЭтот раздел GitLab предназначен для хранения конечных сборок ваших приложений. Он, в том числе, поддерживает хранение пакетов npm, PyPl, NuGet и др. Расположение в репозитории: «Развёртывание» (Deploy) → «Реестр пакетов» (Package registry).
Простейший скрипт для джобы загрузки в реестре пакетов:
variables: PACKAGE_VERSION: "1.2.3" PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/${PACKAGE_VERSION}"upload: stage: upload image: curlimages/curl:latest script: - FILENAME=MyApp - | curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file build/my_app ${PACKAGE_REGISTRY_URL}/${FILENAME}
variables:
PACKAGE_VERSION: "1.2.3"
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/${PACKAGE_VERSION}"
upload:
stage: upload
image: curlimages/curl:latest
script:
- FILENAME=MyApp
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file build/my_app ${PACKAGE_REGISTRY_URL}/${FILENAME}
Публикация релиза
СкопированоВы можете формировать релиз приложения в одноимённом разделе при помощи GitLab CI. Для этого используется отдельный скрипт release. В примере мы получим его с помощью Docker от GitLab.
Этот пример работает в связке с джобой, обеспечивающей загрузку в реестр пакетов (см. раздел выше):
variables: PACKAGE_VERSION: "1.2.3" PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/${PACKAGE_VERSION}" RELEASE_NAME: "MyApp"release: stage: release image: registry.gitlab.com/gitlab-org/release-cli:latest script: - echo "Release ${RELEASE_NAME}" release: name: "Release $PACKAGE_VERSION" description: "Description release $PACKAGE_VERSION" tag_name: "$PACKAGE_VERSION" ref: "$CI_COMMIT_SHA" assets: links: - name: "${RELEASE_NAME}_${PACKAGE_VERSION}" # Путь до файла должен существовать в реестре пакетов url: "${PACKAGE_REGISTRY_URL}/${RELEASE_NAME}"
variables:
PACKAGE_VERSION: "1.2.3"
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/${PACKAGE_VERSION}"
RELEASE_NAME: "MyApp"
release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
script:
- echo "Release ${RELEASE_NAME}"
release:
name: "Release $PACKAGE_VERSION"
description: "Description release $PACKAGE_VERSION"
tag_name: "$PACKAGE_VERSION"
ref: "$CI_COMMIT_SHA"
assets:
links:
- name: "${RELEASE_NAME}_${PACKAGE_VERSION}"
# Путь до файла должен существовать в реестре пакетов
url: "${PACKAGE_REGISTRY_URL}/${RELEASE_NAME}"
Использование самоподписанного сертификата
СкопированоПри работе на локальном домене можно использовать самоподписанный сертификат. Чтобы Docker внутри GitLab CI узнал о нём, укажите переменную ADDITIONAL:
ADDITIONAL_CA_CERT_BUNDLE: | -----BEGIN CERTIFICATE----- MIIGqTCCBJGgAwIBAgIQI7AVxxVwg2kch4d56XNdDjANBgkqhkiG9w0BAQsFADCB ... jWgmPqF3vUbZE0EyScetPJquRFRKIesyJuBFMAs= -----END CERTIFICATE-----
ADDITIONAL_CA_CERT_BUNDLE: |
-----BEGIN CERTIFICATE-----
MIIGqTCCBJGgAwIBAgIQI7AVxxVwg2kch4d56XNdDjANBgkqhkiG9w0BAQsFADCB
...
jWgmPqF3vUbZE0EyScetPJquRFRKIesyJuBFMAs=
-----END CERTIFICATE-----
Также в переменной можно указать путь к файлу сертификата.