Gitlab CI/CD

Терминология

  • Runner (Gitlab Runner) - это сервер, на котором выполняются команды CI.
  • Runner executor - от этого зависит как runner выполняет команды.
  • Pipeline - набор стадий, через которые проходит сборка или тестирование проекта.
  • Job - какое-то действие в Pipeline. Например, запуск unit-тестов.
  • Stage - стадия в Pipeline, которая может выполнять одновременно несколько Job'ов.
  • CI / CD - абревиатура Continious Intergration (автоматическое тестирование) и Continious Deployment (деплой).

Как включить Gitlab CI/CD

Для этого нужно создайть файл .gitlab-ci.yml. Перед использованием, советуем прочесть официальную документацию).

Рекомендации по написанию gitlab-ci.yml

  1. Как можно раньше заложите контроль качества кода: прогон тестов, проверка форматирования, статический анализатор кода.
  2. Файлы для ci, необходимо хранить в директории проекта ./ci (ci/bin, ci/chart и т.д.).
  3. Если для запуска тестов нужно поднять базу или другой сервис, используйте встренную фичу [Services] (https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#define-image-and-services-from-gitlab-ciyml)
  4. Не используйте Makefile для запуска команд в gitlab-ci. Файл Makefile используется только как инструментарий разработчика.
  5. Если нужно писать условия или многстрочный script, вынесите его в отдельный bash файл в директорию ci/bin.
  6. Если нужно передать артефакты из одной стадии в другую, используйте artifacts и dependencies. Обязательно устанавливайте артефактам expires_in. (Документация).
  7. Старайтесь сразу настроить стадию проверки успешности деплоя или артефактов.
  8. Один репозиторий должен создавать только один конечный артефакт или деплоить один сервис.

Рекомендациии по отладке CI

  1. Используйте CI Lint для проверки ошибок в gitlab-ci.yml (Проект > Pipelines > CI Lint).

  2. Результат выполнения CI смотрите через Gitlab, 'CI / CD > Jobs'.

  3. Чтобы посмотреть все переменные окружения (ENV), добавьте CI_DEBUG_TRACE: "true":

job_name:
  variables:
    CI_DEBUG_TRACE: "true"
  1. Выносите код из секции script в bash-файлы, так вы сможете проверять скрипты у себя локально.

  2. Установите локальный gitlab-runner. Ниже пример запуска через docker-executor:

$ cat .gitlab-ci.yml

stages: [quality_check]

run_phpstan:
  stage: quality_check    
  image: phpstan/phpstan     # образ с docker hub
  tags: [docker]                 # чтобы использовать runner на базе docker-executor
  script:
    - ci/bin/run_phpstan.sh

$ gitlab-runner exec docker run_phpstan
...

Типы Gitlab Runner'ов

  • docker-executor (с тегом docker) - позволяют выполнять команды в контейнере любого образа. Этот runner используется по умолчанию. Документация.
  • shell-executor (с тегом shell) - выполняет команды в контексте сервера, где установлен runner. Сейчас на них доступны базовый набор unix-утилит, bash, ansible и docker.

Особенности docker-runner'а

Когда рекомендуется использовать этот runner:

  1. Требуется специфеское окружение для выполнения скрипта. Например, нужен bundle и rubygems.
  2. Нужна изоляция от окружения gitlab-runner'а.

Не рекомендуется в следующих случаях:

  1. Происходит сборка тяжелого docker-образа. Здесь нет поддержки shared-кэша и придется каждый раз делать docker pull и --cache-from, что увеличит время выполнения job'а.

Пример сборки docker образа в docker контейнере (Docker in Docker или DinD):

.dind: &dind         # Создаем mixin с именем 'dind', который можно переиспользовать в нескольких job'ах
  tags: [docker]
  image: docker:dind
  services: ["docker:dind"]
  variables:
    DOCKER_DRIVER: overlay
    DOCKER_HOST: tcp://localhost:2375

build_image:
  <<: *dind         # вставляем содержимое из mixin'а dind
  stage: build  
  dependencies:
    - bundle
  script:
    - docker build
      --cache-from ${BUILDER_IMAGE}
      --build-arg APP_VERSION=${APP_VERSION}
      --build-arg TIMESTAMP=`date +%Y%m%d`
      --tag ${CI_REGISTRY_IMAGE}:latest
      --tag ${CI_REGISTRY_IMAGE}:${APP_VERSION}
      --file ci/docker/Dockerfile.build
      .

FAQ

Как авторизоваться в Gitlab Registry?

Изначально runner'ы не имеют доступа к Gitlab Regitry, требуется авторизовация через docker login:

before_script:
  - docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY};

Параметры CI_JOB_TOKEN и CI_REGISTRY уже прокидывает Gitlab, не нужно определять их вручную (doc).

Пример сборки и push'а в Registry (doc):

docker build -t GITLAB_REGISTRY/group/subgroup/project .
docker push GITLAB_REGISTRY/group/subgroup/project

Рекомендуется использовать режим dind (DockerInDocker) при запуске команд Docker'а.

Как настроить git modules для CI?

Отредактируйте .gitmodules и пропишите относительный путь до репозитория:

[submodule "shared-tools"]
	path = shared-tools
	url = ../../apliteni/k8s/shared-tools.git

В .gitlab-ci.yml добавьте:

variables:
  GIT_SUBMODULE_STRATEGY: recursive

Взято из документации Gitlab.

Как ставить git тег в CI?

В Gitlab еще не реализован механизм создания тегов через CI, но можно использовать API:

#!/usr/bin/env bash
set -e -x -o pipefail

curl -X POST --show-error --fail "https://{GITLAB_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/tags?ref=${CI_COMMIT_SHA}&tag_name=${APP_VERSION}&private_token=${GITLAB_TOKEN}"
  • GITLAB_URL - URL Gitlab'а.
  • CI_PROJECT_ID - ID проекта. Пробрасывается самим Gitlab CI.
  • CI_COMMIT_SHA - SHA коммита. Пробрасывается самим Gitlab CI.
  • APP_VERSION - версия продукта или деплоя.
  • GITLAB_TOKEN - персональный токен (Personal Access Tokens). Желательно использовать не свой токен, а создавать его у пользователя Bot.