Ах, CI/CD-пайплайны — магические конвейеры, которые превращают наши хаотичные коммиты кода в отполированные производственные артефакты. Давайте создадим такой, который заставил бы даже талисмана Go — гофера — весело танцевать. Я обещаю, что это не будет ещё одним туториалом «Hello World» — мы создаём пайплайн, который действительно выполняет полезную работу, сохраняя вашу кодовую базу здоровее, чем запас чайного гриба у хипстера.

Набор инструментов гофера: предварительные требования

Перед тем как начать наше веселье с пайплайнами, вам понадобятся:

  • Учётная запись GitLab (бесплатный уровень подойдёт);
  • Проект на Go, который хотя бы немного интересен;
  • Установленный Docker (потому что контейнеры — это сегодняшние транспортные контейнеры);
  • Кофемашина в пределах 10 шагов (необязательно, но рекомендуется).

Шаг 1: Настройка проекта в стиле гофера

Создайте .gitlab-ci.yml в корне вашего проекта — это ДНК нашего пайплайна. Начнём с чего-то, что заставило бы Роба Пайка одобрительно кивнуть:

image: golang:1.21-alpine
stages:
  - dependencies
  - build
  - test
  - lint
  - deploy
variables:
  GOPROXY: "https://proxy.golang.org"
  GOFLAGS: "-mod=readonly"

Эта основа даёт нам стройность Alpine и правильную конфигурацию модулей Go. Этапы представляют жизненный цикл нашего пайплайна — от управления зависимостями до развёртывания.

Симфония пайплайна

Давайте визуализируем наш шедевр:

graph LR A[Разрешение зависимостей] --> B[Сборка] B --> C[Тестовый набор] B --> D[Linting] C --> E[Развёртывание] D --> E

Это гарантирует, что мы не развернём код, который либо сломан, либо стилистически оскорбителен. Теперь давайте наполним каждый этап заданиями, которые действительно оправдывают своё существование.

Управление зависимостями: Этап взросления

resolve_dependencies:
  stage: dependencies
  script:
    - go mod download
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths:
      - .cache/go-build
      - go/pkg/mod

Это задание подобно ответственному соседу по комнате — оно загружает зависимости один раз и кэширует их для будущих запусков. Ключ кэша гарантирует, что разные ветки не будут мешать друг другу.

Сборка и тестирование: Где резина встречается с дорогой

build_binary:
  stage: build
  script:
    - go build -v -ldflags "-s -w" -o my-app
  artifacts:
    paths:
      - my-app

Наше задание по сборке компилирует двоичный файл с оптимизацией размера и сохраняет его как артефакт. Теперь для тестового набора:

run_tests:
  stage: test
  script:
    - go test -v -race ./...
  coverage: '/^coverage: \d+\.\d+\% of statements/'
  artifacts:
    reports:
      cobertura: coverage.xml

Это запускает тесты с обнаружением гонок и собирает данные о покрытии. Регулярное выражение coverage заставляет GitLab отображать красивые значки покрытия — потому что метрики важны!

Linting: Спа-процедуры для кода

golangci_lint:
  stage: lint
  image: golangci/golangci-lint:latest
  script:
    - golangci-lint run --out-format checkstyle ./... > report.xml
  artifacts:
    reports:
      codequality: report.xml

Используя официальный образ линтера, это задание проводит полную спа-процедуру для вашего кода. Формат checkstyle хорошо интегрируется с отчётами GitLab о качестве кода.

Развёртывание: Освободите гофера!

deploy_production:
  stage: deploy
  image: docker:20.10
  services:
    - docker:20.10-dind
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  script:
    - docker build -t $IMAGE_TAG .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push $IMAGE_TAG
  only:
    - main

Это задание по развёртыванию на базе Docker запускается только при коммитах в ветку main. Оно собирает, помечает тегом и отправляет ваш контейнеризированный Go-приложение в реестр GitLab. Про-совет: добавьте --pull к аргументам сборки, чтобы избежать устаревших базовых образов.

Оптимизация пайплайна: Турбо-режим

  1. Параллельное тестирование: Разбейте ваш тестовый набор на несколько заданий, используя parallel и go test -shuffle.
  2. Предварительный подогрев кэша: Добавьте запланированный пайплайн, который обновляет зависимости ежедневно.
  3. Многоступенчатые сборки: Используйте --target Docker для создания компактных производственных образов.
  4. Управление секретами: Используйте маскированные переменные GitLab для учётных данных.
  5. Запуск пайплайна: Добавьте rules, чтобы предотвратить ненужные сборки при изменении документации.

Когда что-то идёт не так: Советы по отладке

  1. Доступ к оболочке: Используйте SSH в работающие задания для отладки в реальном времени.
  2. Исследование артефактов: Загрузите артефакты сборки, чтобы проверить двоичные файлы.
  3. Локальное тестирование: Запустите gitlab-runner exec docker your-job для локальной проверки.
  4. Визуализация зависимостей: Добавьте задание go mod graph, чтобы отслеживать отношения между модулями.

Финальное countdown

Помните: хороший пайплайн — как надёжный друг — он сообщает, когда что-то не так, но не докучает по мелочам. Наш финальный пайплайн будет:

  1. Поддерживать актуальность зависимостей.
  2. Соблюдать стандарты качества кода.
  3. Обеспечивать покрытие тестами.
  4. Создавать готовые к производству артефакты.
  5. Развёртывать безопасно и повторяемо.

Теперь вперёд и создавайте пайплайны! И помните — если ваш CI занимает больше времени, чем перерыв на кофе, вы делаете что-то не так. Сохраняйте спокойствие и включайте CI/CD!

graph TD A[Коммит] --> B{Пайплайн} B -->|Проход| C[Развёртывание] B -->|Непроход| D[Уведомление в Slack] C --> E[Производство] D --> F[Исправление ошибок] F --> A