Как организовать выполнение стадий pipeline на разных машинах (раннерах) в GitLab CI?

«Как организовать выполнение стадий pipeline на разных машинах (раннерах) в GitLab CI?» — вопрос из категории CI/CD, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В GitLab CI выполнение джобов на разных раннерах контролируется с помощью тегов (tags). Каждому GitLab Runner при регистрации присваиваются теги, описывающие его окружение (например, docker, kubernetes, aws, arm). В конфигурации пайплайна мы указываем, какой тег требуется для конкретной задачи.

Пример .gitlab-ci.yml:

stages:
  - build
  - test
  - security-scan
  - deploy

# Этап сборки выполняется на раннере с Docker, чтобы использовать Docker-in-Docker
build:
  stage: build
  tags:
    - docker
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

# Этап тестов запускаем в Kubernetes-кластере для масштабирования
run-unit-tests:
  stage: test
  tags:
    - kubernetes
  script:
    - echo "Running tests in a dynamically provisioned pod..."
    - ./run_tests.sh

# Сканирование безопасности выполняем на специальном раннере с предустановленными сканерами
sast-scan:
  stage: security-scan
  tags:
    - security
  script:
    - trivy fs --severity HIGH,CRITICAL .

# Деплой в продовое окружение AWS выполняем на раннере с настроенным AWS CLI и правами
deploy-to-prod:
  stage: deploy
  tags:
    - aws
    - production
  script:
    - aws eks update-kubeconfig --name prod-cluster
    - kubectl set image deployment/my-app app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n production
  only:
    - main

Ключевые моменты для надежной конфигурации:

  • Идемпотентность: Каждый job должен быть спроектирован так, чтобы его можно было запустить на любом раннере с подходящим тегом, а не на какой-то конкретной машине.
  • Кеширование и артефакты: Для передачи данных между стадиями, выполняемыми на разных раннерах, необходимо явно объявлять cache или artifacts. Кеш может быть привязан к тегу раннера, а артефакты загружаются/скачиваются из GitLab.
  • Динамическое выделение: Использование раннеров с тегом kubernetes позволяет GitLab динамически создавать pod для выполнения job, что эффективно для эфемерных задач, таких как тесты.