Как настраивал GitLab CI

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

Ответ

Я настраивал GitLab CI/CD для микросервисной архитектуры, где каждый сервис имел свой репозиторий, но общие требования к сборке, тестированию и деплою. Конфигурация строилась на принципах скорости, безопасности и воспроизводимости.

Пример .gitlab-ci.yml для Go-микросервиса, разворачиваемого в Kubernetes:

# 1. Определяем глобальные настройки и образы
default:
  image: golang:1.19-alpine
  before_script:
    - apk add --no-cache git
    - go version

# 2. Разбиваем pipeline на стадии
stages:
  - validate  # Линтинг, проверка зависимостей
  - test      # Unit и интеграционные тесты
  - build     # Сборка артефактов и Docker-образов
  - security  # Сканирование уязвимостей
  - deploy    # Деплой в окружения

# 3. Job'ы для каждой стадии

# 3.1 Валидация
lint:
  stage: validate
  script:
    - go mod tidy
    - go mod verify
    - go fmt ./...
    - go vet ./...
    - staticcheck ./...
  artifacts:
    when: always
    paths:
      - go.sum
    expire_in: 1 week

# 3.2 Тестирование с кэшированием зависимостей и сбором покрытия
test:
  stage: test
  script:
    - go test -race -coverprofile=coverage.txt -covermode=atomic ./...
  coverage: '/total:s*(statements)?s*d+.d+%/'
  artifacts:
    reports:
      cobertura: coverage.xml
    paths:
      - coverage.txt
  cache:  # Кэшируем модули Go для ускорения
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - .go/pkg/mod/

# 3.3 Сборка мультиархитектурного Docker-образа
build:
  stage: build
  image: docker:20.10
  services:
    - docker:20.10-dind
  variables:
    DOCKER_BUILDKIT: 1
    DOCKER_TARGET: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  script:
    - |
      docker buildx create --use
      docker buildx build --platform linux/amd64,linux/arm64 
        --push 
        -t $DOCKER_TARGET 
        -f Dockerfile .
  only:
    - main
    - merge_requests

# 3.4 Сканирование образа на уязвимости с Trivy
trivy-scan:
  stage: security
  image: aquasec/trivy:latest
  variables:
    TRIVY_NO_PROGRESS: "true"
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  allow_failure: false  # Фейл пайплайна при критических уязвимостях

# 3.5 Деплой в staging через Helm
deploy-staging:
  stage: deploy
  image: alpine/helm:3.10
  environment:
    name: staging
    url: https://api-staging.example.com
  script:
    - helm upgrade --install 
        --namespace staging 
        --set image.tag=$CI_COMMIT_SHORT_SHA 
        --values .helm/values-staging.yaml 
        my-service .helm/
  only:
    - main

# 3.6 Ручное подтверждение для деплоя в production
deploy-production:
  stage: deploy
  image: alpine/helm:3.10
  environment:
    name: production
    url: https://api.example.com
  script:
    - helm upgrade --install 
        --namespace production 
        --set image.tag=$CI_COMMIT_SHORT_SHA 
        --values .helm/values-production.yaml 
        my-service .helm/
  when: manual  # Требует ручного подтверждения
  only:
    - main

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

  • BuildKit и Buildx: Для мультиархитектурных сборок и эффективного кэширования слоев.
  • Кэширование зависимостей Go: Значительно ускоряет этап тестирования.
  • Security Scanning: Интеграция Trivy на ранней стадии для блокировки развертывания уязвимых образов.
  • Ручное подтверждение для production: Обязательный гейт для контроля над выпуском.
  • Environments: Использование встроенных окружений GitLab для отслеживания развертываний и их статусов.

Для управления общими шагами (например, деплоем Helm) я выносил их в шаблоны, подключаемые через include, как описано в предыдущем ответе.