GitLab

CI/CD

CI/CD

Pipelines

.gitlab-ci.yml - это yaml файл в котором определяются инструкции для gitlab-ci


Есть список предопределенных переменных которые можно использовать в джобах
https://docs.gitlab.com/ee/ci/variables/predefined_variables.html


Пайплайны это топлевел компоненты ci/cd

Пайпланы состоят из:

Джобы выполняются раннерами, несколько джоб в одном стейдже выполняются параллельно

Если все джобы в стейдже выполнились успешно, то пайплайн переходит на следующий стейдж, если хоть одна джоба зафейлилась, то пайплайн завершается


Types of pipelines

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

Screenshot_2021_02_02-12_49_03-2021-07-03-astnhsnth.png


Ключевое слово 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 требует ручного вмешательства:

Screenshot_2021_02_02-12_49_03-2021-07-03-at-2thththththththct.png

Как видно, можно запустить сразу весь стейдж, либо каждую джобу по отдельности


Каждый пользователь имеет квоты на использование шаред раннеров в личных проектах
Каждая группа также имеет квоты на использование шаред раннеров в проектах внутри этой группы

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"]

Screenshot_2021_02_02-12_49_03-2021-07-03-at-2tthuuhhh.png


Screenshot_2021_02_02-12_49_03-2021-07-0thtaoeuhthththt.gif

Еще есть вот такой чарт с трубами)
Screenshot_2021_02_02-12_49_03-2021-07-03-at-2snthsnthstnhsnthsnth.png

CI/CD

Pipelines/Pipeline schedules

Обычно пайплайны запускаются на основе некоторого события которое должно произойти, например коммит или мердж
Можно делать пайплайны на основе интервалов, например каждый месяц или каждый день или как-то еще

Screenshot_2021_02_02-12_49_03-2021-07-03nthntheoau.png

Чтобы это работало нужно чтобы владелец этого schedule'а имел право мерджить в целевую ветвь


Чтобы указать некоторым джобам что они должны выполняться только когда пайплайн был запущен по расписанию, можно использовать rules

job:on-schedule:
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  script:
    - make world

job:
  rules:
    - if: $CI_PIPELINE_SOURCE = "push"
  script:
    - make build
CI/CD

Pipelines/Triggering pipelines

https://docs.gitlab.com/ee/ci/triggers/

Authentication tokens

Доступные методы аутентификации:


Используя переменную $CI_PIPELINE_SOURCE можно управлять тем какие джобы будут запускаться а какие нет
Она может принимать два значения

В соответствии с тем как был запущен пайплайн


В 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"}}

Screenshot_2021_02_02-12_49_03-2021-07-05-at-1ththththththth.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"

CI/CD

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

Screenshot_2021_02_02-12_49_03-2021-07-05-at-1wmwmwmwm.png

stages:
    - test

c:
    stage: test
    script:
        - echo "Statements - $(echo $RANDOM | head -c 2).$(echo $RANDOM | head -c 2)"

Screenshot_2021_02_02-12_49_03-2021-07-05-at-16sssssss.png

В инете есть готовые регулярки для разных систем тестирования (в доке гитлаба тоже есть)

В разделе analytics > repository будет собираться график из значений coverage

Иногда coverage может не парситься из-за цветного вывода, нужно убрать цветность у тестирующей утилиты


В Settings > CI/CD > General Pipelines можно включить функции благодаря которой лишние пайплайны будут отменяться (не заработало)


Возможные статусы пайплайна:

Про бейджи на основе этих статусов
https://docs.gitlab.com/ee/ci/pipelines/settings.html#pipeline-status-badge

CI/CD

Pipelines/Pipeline architecture

Пайплайн это основной строительный блок ci/cd в gitlab

Дальше про три осноных пути структурирования пайплайнов (у каждого свои преимущества)

basic pipelines

Screenshot_2021_02_02-12_49_03-2021-07-05-santoheusnatoehus.png

На каждом стейдже джобы запускаются одновременно
К следующему стейджу переходит когда предыдущий полностью отработал без ошибок

Directed Acyclic Graph Pipelines

Screenshot_2021_02_02-12_49_03-2021-07-05-atththththth.png

Если очень важна эффективность и хочется запускать все как можно скорее, то можно использовать DAG
Используя needs определяем зависимости между джобами
Гитлаб будет знать зависимости и сможет запускать джобы согласно им, это будет быстрее

Child / Parent Pipelines

Screenshot_2021_02_02-12_49_03-2021-07-05-at-2ththththththteee.png

CI/CD

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 запустит создание бэкапа

Screenshot_2021_02_02-12_49_03-2022-03-29-at-snthsnthstnh.png

Получается вот такой архив

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

Системные требования: