GitLab
- CI/CD
- Pipelines
- Pipelines/Pipeline schedules
- Pipelines/Triggering pipelines
- Pipelines/Pipeline settings
- Pipelines/Pipeline architecture
- Pipelines/Pipeline efficiency
- Backup & Restore
- Self-hosted GitLab in cloud with K8S
CI/CD
Pipelines
.gitlab-ci.yml
- это yaml файл в котором определяются инструкции для gitlab-ci
Есть список предопределенных переменных которые можно использовать в джобах
https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
Пайплайны это топлевел компоненты ci/cd
Пайпланы состоят из:
- Jobs - определяют что делать (сборка, тесты итд)
- Stages - определяют когда запускать джобы (запускать тесты после сборки итд)
Джобы выполняются раннерами, несколько джоб в одном стейдже выполняются параллельно
Если все джобы в стейдже выполнились успешно, то пайплайн переходит на следующий стейдж, если хоть одна джоба зафейлилась, то пайплайн завершается
Types of pipelines
- Basic pipelines - запускает все в каждом стейдже по порядку
- Directed Acyclic Graph Pipeline (DAG) pipelines - базируется на отношениях между джобами и благодаря этому может работать быстрее чем basic pipeline
- Multi-project pipelines - комбинация пайплайнов из разных проектов
- Parent-Child pipelines - можно разбить сложный пайплайн на один родительский и несколько дочерних сабпайплайнов которые будут триггериться родительским (все в рамках одного проекта)
- Pipelines for Merge Requests - запускаются только для MR'ов, а не для каждого коммита
- Pipelines for Merged Results - are merge request pipelines that act as though the changes from the source branch have already been merged into the target branch
- Merge Trains - используй pipelines for merged results чтобы ставить их в очередь на слияние один за другим
Configure a pipeline
Пайплайн и его компоненты конфигурируются в конфиге для каждого проекта отдельно
Когда раннер подбирает джобу, гитлаб предоставляет раннеру метадату о джобе (ветвь, коммит, тэг итд) и раннер на основе этого что-то делает
Pipeline type | Refspecs |
---|---|
Pipeline for Branches |
+<sha>:refs/pipelines/<id> and +refs/heads/<name>:refs/remotes/origin/<name>
|
Pipeline for Tags |
+<sha>:refs/pipelines/<id> and +refs/tags/<name>:refs/tags/<name>
|
Pipeline for Merge Requests | +<sha>:refs/pipelines/<id> |
Пайплайны могут быть также запущены вручную с вручную указанными переменными
Когда пайплайн запускается вручную, то страница 'Run Pipeline' показывает все top-level переменные определенные в .gitlab-ci.yml
с description и value и позволяет их переопределить для этого ручного запуска
Пример пайплайна:
variables:
DEPLOY_ENVIRONMENT:
value: "staging" # Deploy to staging by default
description: "The deployment target. Change this variable to 'canary' or 'production' if needed."
THIS_VAR_WILL_ALSO_BE_SHOWN:
value: "testvalue"
description: "test descr for test var"
THIS_VAR_WILL_NOT_BE_SHOW: "value"
stages:
- document
pages:
stage: document
image:
name: mjdk/diagrams:latest
entrypoint:
- env
script:
- python docs/components.py
- mkdir -p public
- cp eks_cluster.png public/
artifacts:
paths:
- public
Ключевое слово when
может принимать значение manual
: when:manual
Тогда джоба не будет запускаться автоматически, а только по клику пользователя
stages:
- test
- test2
- final
a:
stage: test
script:
- echo 0
b:
stage: test
script:
- echo 1
c:
stage: test
script:
- echo 2
d:
stage: test2
script:
- echo 3
e:
stage: final
when: manual
script:
- echo 4
f:
stage: final
when: manual
script:
- echo 5
Видно что final
требует ручного вмешательства:
Как видно, можно запустить сразу весь стейдж, либо каждую джобу по отдельности
Каждый пользователь имеет квоты на использование шаред раннеров в личных проектах
Каждая группа также имеет квоты на использование шаред раннеров в проектах внутри этой группы
0 1 2 3 4 5 6 7
AAAAAAA
BBBBBBB
CCCC
Длительность пайплайна считается так:
(4 - 1) + (7 - 6) => 4
Pipeline quota usage считается так:
2 + 2 + 1 => 5
Visualize pipelines
stages: ["pre", "test", "test2", "final"]
pre:
stage: pre
script: ["echo pre"]
a:
stage: test
needs: ["pre"]
script: ["echo 0"]
b:
stage: test
needs: ["pre"]
script: ["echo 1"]
c:
stage: test
needs: ["pre"]
script: ["echo 2"]
d:
stage: test2
when: manual
needs: ["pre", "a", "b", "c"]
script: ["echo 3"]
e:
stage: final
needs: ["pre", "a", "b", "c", "d"]
script: ["echo 4"]
f:
stage: final
needs: ["d"]
script: ["echo 5"]
Еще есть вот такой чарт с трубами)
Pipelines/Pipeline schedules
Обычно пайплайны запускаются на основе некоторого события которое должно произойти, например коммит или мердж
Можно делать пайплайны на основе интервалов, например каждый месяц или каждый день или как-то еще
Чтобы это работало нужно чтобы владелец этого schedule'а имел право мерджить в целевую ветвь
Чтобы указать некоторым джобам что они должны выполняться только когда пайплайн был запущен по расписанию, можно использовать rules
job:on-schedule:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- make world
job:
rules:
- if: $CI_PIPELINE_SOURCE = "push"
script:
- make build
Pipelines/Triggering pipelines
https://docs.gitlab.com/ee/ci/triggers/
Authentication tokens
Доступные методы аутентификации:
- Trigger token - уникальный токен, который генерируется при добавлении нового триггера (может быть использован для webhook)
- CI job token - тот же токен можно использовать внутри gitlab-ci.yml через переменную
$CI_JOB_TOKEN
Используя переменную $CI_PIPELINE_SOURCE
можно управлять тем какие джобы будут запускаться а какие нет
Она может принимать два значения
pipeline
trigger
В соответствии с тем как был запущен пайплайн
В Settings > CI/CD > Triggers можно создать новый триггер
Будет создан токен который можно будет использовать в gitlab-ci.yml
Чтобы стриггерить триггер нужно отправить POST в API endpoint
POST /projects/:id/trigger/pipeline
Айди можно посмотреть в Settings > CI/CD
vandud@macbook: ~ [0]$ curl -X POST -F token=064f70a02674ffba2a476144d39fdd -F ref=main https://gitlab.com/api/v4/projects/27896306/trigger/pipeline
{"id":331734189,"project_id":27896306,"sha":"cfd5def867391ad8635ab7216492f6742f6240f0","ref":"main","status":"created","created_at":"2021-07-05T07:19:28.256Z","updated_at":"2021-07-05T07:19:28.256Z","web_url":"https://gitlab.com/vandud/gitlabci-project-dependency-test/-/pipelines/331734189","before_sha":"0000000000000000000000000000000000000000","tag":false,"yaml_errors":null,"user":{"id":2745541,"name":"Ivan Dudin","username":"vandud","state":"active","avatar_url":"https://assets.gitlab-static.net/uploads/-/system/user/avatar/2745541/avatar.png","web_url":"https://gitlab.com/vandud"},"started_at":null,"finished_at":null,"committed_at":null,"duration":null,"queued_duration":null,"coverage":null,"detailed_status":{"icon":"status_created","text":"created","label":"created","group":"created","tooltip":"created","has_details":false,"details_path":"/vandud/gitlabci-project-dependency-test/-/pipelines/331734189","illustration":null,"favicon":"https://gitlab.com/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png"}}
Токен и ref можно указывать ключами в самом урле
Можно использовать webhook payload при триггеринге, а внутри пайплайна использовать этот пэйлоад через переменную окружения $TRIGGER_PAYLOAD
Можно передать в webhook'e для пайплайна переменные окружения и они будут доступны в пайплайне
Это можно использовать например для идентификации причин запуска пайплайна т.к. переменная видна в web-ui (положить в переменную описание причины)
Можно добавить определенным джобам условие на наличие определенной переменной
upload_package:
stage: package
script:
- if [ -n "${UPLOAD_TO_S3}" ]; then make upload; fi
curl --request POST \
--form token=TOKEN \
--form ref=main \
--form "variables[UPLOAD_TO_S3]=true" \
"https://gitlab.example.com/api/v4/projects/9/trigger/pipeline"
А еще можно засунуть курл в крон и получится "Pipeline schedules"
Pipelines/Pipeline settings
По умолчанию в пайплайнах используется git strategy - fetch, потому что это быстрее. Можно это переопределить на clone, это будет медленнее, но рабочая копия репозитория будет свежей
Это указывается в переменной GIT_STRATEGY
Ограничение через git depth
может ускорить выполнение пайплайна
Глубину можно задавать через переменную GIT_DEPTH
Можно задать таймаут джобе (1h by default) через settings > ci_cd
В этом же разделе настроек можно изменить имя ci/cd yml файла .gitlab-ci.yml -> my-ci.conf.yml
(должен кончаться на .yml
)
В этом же разделе настроек есть пункт "Test coverage parsing"
В нем задается регулярка которой будет парситься вывод джоб
Подходящий под регулярку вывод будет выведен как Coverage
stages:
- test
c:
stage: test
script:
- echo "Statements - $(echo $RANDOM | head -c 2).$(echo $RANDOM | head -c 2)"
В инете есть готовые регулярки для разных систем тестирования (в доке гитлаба тоже есть)
В разделе analytics > repository будет собираться график из значений coverage
Иногда coverage может не парситься из-за цветного вывода, нужно убрать цветность у тестирующей утилиты
В Settings > CI/CD > General Pipelines можно включить функции благодаря которой лишние пайплайны будут отменяться (не заработало)
Возможные статусы пайплайна:
- pending
- running
- passed
- failed
- skipped
- canceled
- unknown
Про бейджи на основе этих статусов
https://docs.gitlab.com/ee/ci/pipelines/settings.html#pipeline-status-badge
Pipelines/Pipeline architecture
Пайплайн это основной строительный блок ci/cd в gitlab
Дальше про три осноных пути структурирования пайплайнов (у каждого свои преимущества)
- basic - хорошо для простого проекта где все конфиги легкодоступны из одного места
- directed acyclic graph - хорошо для больших и сложных проектов где требуется эффективность
- child/parent pipelines - хорошо для монореп и проектов где много независимых компонентов
basic pipelines
На каждом стейдже джобы запускаются одновременно
К следующему стейджу переходит когда предыдущий полностью отработал без ошибок
Directed Acyclic Graph Pipelines
Если очень важна эффективность и хочется запускать все как можно скорее, то можно использовать DAG
Используя needs
определяем зависимости между джобами
Гитлаб будет знать зависимости и сможет запускать джобы согласно им, это будет быстрее
Child / Parent Pipelines
Pipelines/Pipeline efficiency
Быстрые пайплайны экономят время разработчиков и деньги
Identify bottlenecks and common failures
Простейшие индикаторы неэффективности пайплайнов - время работы джоб, стейджей и самих пайплайнов
Общее время пайплайна зависит от количества стейджей и джоб, зависимостей между джобами
Также на скорость влияют раннеры
Их доступность, их ресурсы, installation time, размер образа (docker), сетевые задержки
Pipeline analysis
Анализ пайплайнов может помочь вычислить финансовые утечки
Например раннер который запущен в облаке на слишком мощной мащине - оплачивается ресурсов больше чему нужно
Или наоборот недостаток ресурсов делает пайплайн медленным
Можно смотреть на DAG визуализацию и вычислять блокеры
Можно мониторить пайплайны прометеем через апи)))
Можно мониторить раннеры (cpu, network, memory и все такое)
можно проанализировать storage usage, артефакты, expire_in конфиги этих артифактов (пайплайны генерят данные, им нужно их куда-то складывать, поэтому место на раннере важно), container registry usage, package registry usage
Можно быстрее фейлиться, например использовать линтеры и прочее чтобы на этих быстрых джобах отсекать заведомо нерабочие пайплайны (из-за проблем с синтаксисом или еще чем-то легко проверяемым, пайплайн может зависнуть на долгое время, а благодаря линтерам подобные проблемы мы увидим на первых этапах работы пайплайна)
Можно использовать кэширование, если зависимые джобы делают мало изменений то можно использовать кэш (например тянуть node_modules из джобы в джобу а не выкачивать каждый раз) cache
Скачивание и инициализация имаджей может также занимать время, поэтому круто анализировать размеры имаджей, сеть по которой они доставляются, если используется клауд то круто использовать облачный registry
Круто билдить мелкие образы на мелкие задачи, а не большие образы на комплексные задачи
Билдить мелкие образы это отдельное искусство, гугли отдельно
Backup & Restore
You can only restore a backup to exactly the same version and type (CE/EE) of GitLab on which it was created
Версию и тип можно засунуть в имя файла бэкапа
Бэкапы складываются в backup_path
root@gitlab-new:/etc/gitlab# cat gitlab.rb | grep backup_path
gitlab_rails['backup_path'] = "/var/opt/gitlab/backups"
Выглядят они вот так
root@gitlab-new:/etc/gitlab# ls /var/opt/gitlab/backups
1636411695_2021_11_08_13.2.4_gitlab_backup.tar 1636413943_2021_11_08_14.0.12_gitlab_backup.tar 1636416295_2021_11_09_14.4.2_gitlab_backup.tar 1636419165_2021_11_09_14.1.7_gitlab_backup.tar
1636413054_2021_11_08_13.12.15_gitlab_backup.tar 1636414740_2021_11_08_14.1.7_gitlab_backup.tar 1636416920_2021_11_09_14.2.6_gitlab_backup.tar
root@gitlab-new:/etc/gitlab#
Команда - sudo gitlab-backup create
запустит создание бэкапа
Получается вот такой архив
root@gitlab-new:/var/opt/gitlab/backups# tar --list -f 1648556739_2022_03_29_14.4.2_gitlab_backup.tar | grep -v 'repositories/'
db/
db/database.sql.gz
uploads.tar.gz
builds.tar.gz
artifacts.tar.gz
pages.tar.gz
lfs.tar.gz
backup_information.yml
Но в нем нет конфигов
/etc/gitlab/gitlab-secrets.json
/etc/gitlab/gitlab.rb
Их нужно забэкапить отдельно (в них есть чувствительная инфа, надо быть аккуратным)
Существуют разные backup options
Например можно бэкапить через временные файлы, а можно гнать данные напрямую в tar (итд, опций полно)
Гитлаб может отправлять бэкап в удаленное хранилище (например в s3)
В /etc/gitlab/gitlab.rb нужно прописать:
gitlab_rails['backup_upload_connection'] = {
'provider' => 'AWS',
'region' => 'ru-central1',
'aws_access_key_id' => 'YCAJExaoeuaoeuTM_m8BrB',
'aws_secret_access_key' => 'YCMpK7kaoeuaoeu3_Hxhpr9XwH7__mmG',
'endpoint' => 'https://storage.yandexcloud.net',
'path_style' => true
}
gitlab_rails['backup_upload_remote_directory'] = 'zeen-backup-gitlab'
И вот такую хрень в крон
root@gitlab-new:/etc/gitlab# crontab -l | egrep -v '^#'
0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1
Self-hosted GitLab in cloud with K8S
Системные требования:
- Linux
- Redis
- PostgreSQL