CI/CD для Go проектов: GitHub Actions от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

CI/CD для Go проектов с GitHub Actions: полное руководство

Автоматизация процессов сборки, тестирования и развертывания — неотъемлемая часть современной разработки на Go (Golang). GitHub Actions предоставляет мощный и гибкий инструментарий для построения пайплайнов CI/CD прямо в вашем репозитории. В этой статье мы разберем, как настроить полный цикл непрерывной интеграции и доставки для Go-проекта, от простого тестирования до автоматического деплоя.

Что такое CI/CD и почему это важно для Go?

CI (Continuous Integration) — это практика частого слияния кода в основную ветку с автоматической сборкой и тестированием. CD (Continuous Delivery/Deployment) — автоматическое развертывание готового приложения.

Для Go-проектов CI/CD особенно полезен, так как:

  • Go компилируется в статический бинарник, что упрощает деплой
  • Быстрое тестирование благодаря нативной скорости Go
  • Автоматическая проверка линтерами и форматирования (gofmt, golangci-lint)
  • Возможность мультиплатформенной сборки (Linux, macOS, Windows)

Основы GitHub Actions для Go

GitHub Actions использует YAML-файлы в директории .github/workflows. Каждый файл описывает один или несколько workflows (пайплайнов).

Рассмотрим базовый workflow для Go-проекта:

name: Go CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.22'
    
    - name: Cache Go modules
      uses: actions/cache@v4
      with:
        path: ~/go/pkg/mod
        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
        restore-keys: |
          ${{ runner.os }}-go-
    
    - name: Install dependencies
      run: go mod download
    
    - name: Run tests
      run: go test -v -race -coverprofile=coverage.out ./...
    
    - name: Upload coverage
      uses: actions/upload-artifact@v4
      with:
        name: coverage
        path: coverage.out

Этот workflow запускается при пуше в main/develop и на pull request. Он устанавливает Go, кэширует зависимости, запускает тесты с флагами -race (детектор гонок) и -coverprofile (покрытие кода).

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

Для поддержания качества кода добавим проверку линтером. golangci-lint — стандарт де-факто для Go.

  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.22'
    - name: golangci-lint
      uses: golangci/golangci-lint-action@v6
      with:
        version: latest
        args: --timeout=5m ./...

Мультиплатформенная сборка полезна, если ваше приложение должно работать на разных ОС:

  build:
    needs: [test, lint]
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        goarch: [amd64, arm64]
    
    runs-on: ${{ matrix.os }}
    
    steps:
    - uses: actions/checkout@v4
    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.22'
    - name: Build
      run: |
        GOARCH=${{ matrix.goarch }} go build -v -o myapp-${{ matrix.os }}-${{ matrix.goarch }} ./cmd/app

Обратите внимание: для Windows нужно будет скорректировать имя выходного файла (добавить .exe). Используйте if runner.os == 'Windows' или задайте имя через переменные.

Автоматический деплой Go-приложения

Для деплоя рассмотрим два популярных сценария: публикация Docker-образа и загрузка бинарника на сервер.

Сценарий 1: Docker Hub

  deploy-docker:
    needs: [build]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Log in to Docker Hub
      uses: docker/login-action@v3
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
    
    - name: Build and push
      uses: docker/build-push-action@v6
      with:
        context: .
        push: true
        tags: |
          ${{ secrets.DOCKER_USERNAME }}/myapp:latest
          ${{ secrets.DOCKER_USERNAME }}/myapp:${{ github.sha }}

Для работы потребуется Dockerfile в корне проекта. Пример минимального Dockerfile для Go:

FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp ./cmd/app

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]

Сценарий 2: Прямая загрузка на сервер через SSH

  deploy-ssh:
    needs: [build]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    
    steps:
    - name: Download artifact
      uses: actions/download-artifact@v4
      with:
        name: myapp-linux-amd64
    
    - name: Deploy via SSH
      uses: easingthemes/ssh-deploy@v5
      with:
        SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
        REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
        REMOTE_USER: ${{ secrets.REMOTE_USER }}
        SOURCE: "myapp-linux-amd64"
        TARGET: "/opt/myapp/"
        ARGS: "-rltgoDzvO"
    
    - name: Restart service
      uses: appleboy/ssh-action@v1
      with:
        host: ${{ secrets.REMOTE_HOST }}
        username: ${{ secrets.REMOTE_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          sudo systemctl restart myapp
          echo "Service restarted successfully"

Лучшие практики и секреты

Блоги

Рекомендаций по книгам