Перейти к содержанию

Gitlab

Описание

Распределенная система хранения репозиториев, с большим инструментарием для работы с ними.

Дает возможность компаниям развернуть свой инстанс Gitlab для своих проектов.

Предоставляет систему построения CI/CD (Gitlab CI)

Содержит в себе встроенные хранилища для репозиториев, образов Docker, раннеров, Jira и другие инструменты.


Gitlab CI

Описание

Gitlab CI - инструмент для автоматизации процессов разработки и доставки ПО.

Позволяет автоматически собирать, тестировать и деплоить ПО.


Основные атрибуты pipeline

pipeline

pipeline - это набор задач, которые выполняются в определенном порядке.

Сам пайплайн описывается в файле который лежит в корне проекта (под служебным названием .gilab-ci.yml, но может называться как угодно)

pipeline состоит из самого pipeline. Внутри него есть stages (этапы) и внутри stages лежат сами задачи (jobs)

Любой gitlab-ci.yml начинается с описания stages

stages:
 - lint
 - build
 - test
 - deploy

Скрытые stages

Существует два специальных stages: .pre, .post.

Эти stages выполняются всегда в начале и всегда в конце pipeline. В них никаких jobs нет.

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

stages:
 - build

build app:
 stage: build
 script:
  - command_to_build my_app

Variables - переменные используются для передачи изменяемых данных внутрь задачи. Указанные переменные устанавливаются переменными окружения внутри раннера.

stages:
 - build

build app:
 variables:
  POSTGRES_DB: appname_db
 stage: build
 script:
  - command_to_build my_app --arg POSTGRES_DB=${POSTGRES_DB}

Globals - большинство атрибутов, можно вынести из секции описания задачи на верхний уровень. Тогда они станут глобальными параметрами по-умолчанию. Их все еще можно переопределить внутри джобы.

stages:
 - build

variables:
  POSTGRES_DB: appname_db

build app:
 stage: build
 script:
  - command_to_build my_app --arg POSTGRES_DB=${POSTGRES_DB}

Пример pipeline

В папке проекта создаем файл .gitlab-ci.yml:

# описание stages
stages:
 - lint
 - build
 - test
 - deploy

# описание job под названием docker build
docker build:
 # название этапа
 stage: build
 # команды для выполнения
 script: 
  - docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
  - docker build -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG} .
  - if [[ "${CI_COMMIT_BRANCH}" == "${CI_DEFAULT_BRANCH}" ]] ; then
        docker tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG} ${CI_REGISTRY_IMAGE}:latest;
        docker push ${CI_REGISTRY_IMAGE}:latest; fi
  - if [[ -z "${CI_COMMIT_TAG}" ]] ; then
        docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG};
    else
        docker tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG} ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG};
        docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}; fi
  needs:
   - ["django tests"]
  tags:
   - docker

 django tests:
  image: python:3.9-alpine
  stage: test
  script:
   - pip install -r requirements.txt
   - mkdir db
   - python manage.py test
  # тег gitlab-runner для этого job
  tags:
   - dev-shell


Services сайдкары для контейнера

Зачем нужны сервисы

Сервис - это дополнительный контейнер, который поднимается вместе с основным, в момент выполнения задачи.

  • Контейнеры связываются между собой (links)
  • К сервису имеется доступ во время сборки

Пример сервиса postgresql

Описываем сервис, после чего вызываем подключение к нему из задачи

Обращение к хосту выполняется по имени сервиса, если не определено иное имя через alias.

services:
 - postgres

variables: 
  POSTGRES_DB: custom_db
  POSTGRES_USER: custom_user
  POSTGRES_PASSWORD: custom_pass

connect:
 script:
   - export PGPASSWORD=$POSTGRES_PASSWORD
   - psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 'OK' AS status;"

Различные версии приложения

Можно использовать разные версии одного сервиса для приложения.

test:2.6:
 image: ruby:2.6
 services:
  - postgres:11.7
 script:
  - bundle exec rake spec

test:2.7:
 image: ruby:2.6
 services:
  - postgres:12.2
 script:
  - bundle exec rake spec

Конфигурирование

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

Например, переопределить имя и стартовые команды.

default:
 image:
   name: ruby:2.6
   entrypoint: ["/bin/bash"]

 services:
  - name: my-postgres:11.7
    alias: db-postgres
    entrypoint: ["/usr/local/bin/db-postgres"]
    command: ["start"]

test:
 script:
  - bundle exec rake spec
variables:
 HTTP_PROXY: "https://10.1.1.1:8090"
 POSTGRES_DB: "my_custom_db"
 POSTGRES_USER: "postgres"
 POSTGRES_PASSWORD: "example"
 PGDATA: "/var/lib/postgresql/data"
 POSTGRES_INITDB_ARGS: "--encoding=UTF8 --data-checksums"

services:
 - name: postgres:11.7

test:
 script:
  - bundle exec rake spec

Класический пример сервиса: dind

dind - docker in docker

Используется для доступа к docker-daemon изнутри контейнера с docker cli.

Для этого также нужно определить переменную DOCKER_HOST.

docker_build:
 stage: build
 image: docker:stable
 services:
  - docker:dind
 script:

Сохранение результатов

Работа с артефактами

Cache - сохранение результатов работы раннера между задачами одного этапа. Можно использовать S3-хранилище.

  • можно задавать любой ключ
  • можно использовать только в рамках одного раннера
  • нельзя скачать в виде артефакта

Artifacts - сохранение результатов сборок и работы раннера для последующего использования. Можно скачать чеерз интерфейс. Используется для передачи состояния между этапами.

  • множество вариаций конфигурирования
  • доступно между раннерами
  • можно скачать через UI
  • можно выкладывать как репорты

Кастомизация пайплайнов

Дополнительные параметры задач

before_script/after_script - то же самое, что и script, но выполняется либо перед либо после него

when/rules/workflow - правила для параметризации задач: можно задать условия при которых пайплайн будет запускаться

when - условие запуска задачи

Job в ручном режиме

deploy_job:
 stage: deploy
 script:
  - make deploy
 when: manual

Job запускается сама

cleanup_job:
 stage: cleanup 
 script:
  - cleanup after jobs
 when: always

Rules - задание дополнительных условий для job

tests_codestyle_check:
 stage: test
 script: 
  - composer install -q
  - php vendor/bin/phpcs

 rules:
  - if: $CI_JOB_STAGE == "test"
    when: always
  - if: $VAR == "string value"
    when: always

Workflow - общие правила для всего pipeline

workflow:
 rules:
  - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
    when: never
  - if: $CI_COMMIT_BRANCH`

Predefined CI/CD variables

Переменная Описание
gitlab-ci-token специальный пользователь, которого GitLab создает автоматически только на время работы job. Пример использования: docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN}
${CI_JOB_TOKEN}=[MASKED] уникальный токен конкретной job. После завершения job становится недействительным
${CI_PROJECT_NAME}=for_test название репозитория
${CI_REGISTRY}=registry.gitlab.com адрес Registry GitLab
${CI_REGISTRY_IMAGE}=registry.gitlab.com/username/for_test адрес образа в GitLab Container Registry
${CI_COMMIT_REF_SLUG}=main имя ветки преобразованное в безопасный формат (было feature/docker стало feature-docker). Часто используется docker build -t app:$CI_COMMIT_REF_SLUG .
${CI_COMMIT_REF_NAME}=main на какой ветке или теге сейчас выполняется pipeline
${CI_COMMIT_SHA}=1009a5559f4e23c862a18eddc4fbb5f3d3e1534d полный SHA коммита
${CI_COMMIT_BRANCH}=main ветка, для которой сейчас выполняется pipeline. Она меняется в зависимости от того, где ты сейчас находишься
${CI_DEFAULT_BRANCH}=main название основной ветки, используется чтобы не хардкодить на случай если дефолтная ветка изменит свое название
${CI_COMMIT_TAG} название тега
${CI_PIPELINE_SOURCE=push / merge_request_event откуда запустился pipeline (push/merge_request_event\schedule\web)
${CI_PIPELINE_URL}=https://gitlab.com/username/for_test/-/pipelines/2666589838} ссылка на pipeline (можно отправлять в telegram)
${CI_JOB_NAME}=show variables название job
${CI_PROJECT_DIR}=/home/gitlab-runner/builds/pJwjkgAw6/0/andreyd97/for_test куда runner склонировал проект. Все команды выполняются отсюда
---

Советы

1) По максимуму использовать переменные (где возможно)

Плохо:

rules:
  - if: '$CI_COMMIT_BRANCH == "main"'
Правильно:
rules:
  - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'