Продвинутый CI/CD для Go проектов с GitHub Actions
Автоматизация сборки, тестирования и развертывания — основа современной Go-разработки. Базовые пайплайны хороши для старта, но когда проект растет, требуются продвинутые техники: кэширование зависимостей, параллельные джобы, матричные сборки под разные ОС и архитектуры, публикация артефактов в Docker Hub и умный деплой. В этой статье мы разберем, как настроить GitHub Actions для Go-проекта на профессиональном уровне.
1. Кэширование Go-модулей и бинарников
Каждый запуск пайплайна может скачивать десятки мегабайт зависимостей. Чтобы ускорить процесс, используем встроенное кэширование GitHub Actions для go mod и кэша сборки.
name: Go CI (продвинутый)
on: [push, pull_request]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Установка Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Кэширование Go-модулей
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Загрузка зависимостей
run: go mod download
- name: Линтер (golangci-lint)
uses: golangci/golangci-lint-action@v6
with:
version: latest
- name: Тесты с покрытием
run: go test -v -race -coverprofile=coverage.out ./...
- name: Сборка бинарника
run: go build -o myapp ./cmd/app
Ключ hashFiles('**/go.sum') инвалидирует кэш только при изменении зависимостей. Кэш сборки (~/.cache/go-build) сохраняет скомпилированные объекты, ускоряя пересборку.
2. Матричные сборки: тестирование под разные версии Go и ОС
Go-проекты часто должны работать на Linux, macOS и Windows, а также поддерживать несколько версий языка. Матрица (matrix strategy) позволяет запускать параллельные джобы для каждой комбинации.
jobs:
matrix-test:
strategy:
matrix:
go-version: ['1.21', '1.22', '1.23']
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Установка Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Тесты
run: go test ./...
Этот подход выявляет проблемы совместимости на разных платформах. Для Windows может потребоваться дополнительная настройка путей и переносов строк. Добавьте fail-fast: false, чтобы остальные джобы продолжали работу, даже если одна упала.
3. Публикация Docker-образа и GitHub Release
После успешного тестирования логично опубликовать артефакты: Docker-образ в Docker Hub (или GitHub Container Registry) и бинарник в GitHub Release. Рассмотрим оба сценария.
Публикация Docker-образа
Создадим джобу, которая запускается только после тестов и только при пуше в main или при создании тега.
jobs:
docker:
needs: [build-and-test]
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Логин в Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Сборка и пуш образа
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/myapp:latest
${{ secrets.DOCKER_USERNAME }}/myapp:${{ github.sha }}
Не забудьте создать Dockerfile в корне проекта. Для Go-приложений часто используют multi-stage сборку, чтобы образ был минимальным.
Создание GitHub Release
Для бинарных артефактов используем softprops/action-gh-release. Сначала собираем бинарники под разные платформы с помощью go build с указанием GOOS и GOARCH.
jobs:
release:
needs: [build-and-test]
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Сборка под Linux и macOS
run: |
GOOS=linux GOARCH=amd64 go build -o myapp-linux ./cmd/app
GOOS=darwin GOARCH=amd64 go build -o myapp-darwin ./cmd/app
- name: Создание релиза
uses: softprops/action-gh-release@v2
with:
files: |
myapp-linux
myapp-darwin
generate_release_notes: true
Теперь при пуше тега вида v1.2.3 автоматически создается релиз с бинарниками и заметками из коммитов.
4. Условный деплой и окружения
Продвинутый пайплайн должен уметь деплоить в разные окружения (staging, production) в зависимости от ветки или тега. Используем GitHub Environments для защиты sensitive-данных.
jobs:
deploy:
needs: [docker]
runs-on: ubuntu-latest
environment:
name: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
url: ${{ steps.deploy.outputs.url }}
steps:
- name: Деплой на сервер
run: |
# Пример: SSH-команда для обновления контейнера
ssh user@server "docker pull myapp:latest && docker compose up -d"
Для staging можно использовать отдельный сервер или ветку develop. В секции environment можно настроить обязательные ревьюверов и тайм-ауты — это защитит продакшн от случайного деплоя.
Заключение
Продвинутый CI/CD с GitHub Actions для Go-проектов — это