У цій статті ми разом налаштуємо мультиплатформений CI для Go-проєктів на Linux, який компілює під amd64 та arm64 за допомогою Docker Buildx і QEMU, автоматично ганяє тести та публікує multi-arch образи. Це означає, що ваш бінарник або контейнер працюватимуть і на сервері x86_64, і на ARM-пристроях на кшталт Raspberry Pi 🚀
Що саме ми побудуємо
Пайплайн включатиме:
- автотести для Go в Linux;
- емуляцію інших архітектур через QEMU під час збірки й тестування;
- multi-arch Docker-образ через Buildx та маніфест-список;
- зручну автоматизацію задач через GitHub Actions.
Ми працюємо з інструментами Docker на Linux, QEMU та BuildKit. Для коду — Go 1.22+. Такий підхід органічно вписується у сучасну розробку на Linux і масштабування CI.
Передумови
- Оновлений Linux-дистрибутив із правами sudo;
- Встановлені Docker і Git;
- Обліковий запис у Docker Hub або GHCR для публікації образів;
- Репозиторій з Go-кодом (модуль). Це — класична Go в Linux історія.
# Ubuntu/Debian: базові речі
sudo apt update -y
sudo apt install -y git curl ca-certificates qemu-user-static
# Встановіть Docker, якщо ще не встановлено (офіційний скрипт)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker "$USER" # перелогіньтеся після цього
docker --version
qemu-aarch64 --version
Основний How-to
1) Багатостадійний Dockerfile з ціллю для тестів
Створимо Dockerfile, де є окрема стадія test: при її збірці тести запускаються усередині контейнера для вказаної архітектури. Якщо впадуть — збірка зупиниться.
cat > Dockerfile <<'EOF'
# syntax=docker/dockerfile:1.6
ARG GO_VERSION=1.22
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-bookworm AS base
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Тестова стадія: запускає `go test` під цілевою архітектурою
FROM base AS test
ARG TARGETOS TARGETARCH
ENV GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go test ./... -count=1
# Прод-стадія: будуємо статичний бінарник і пакуємо в мінімальний образ
FROM base AS build
ARG TARGETOS TARGETARCH
ENV GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -trimpath -ldflags="-s -w" -o /out/app ./cmd/app
FROM gcr.io/distroless/base-debian12 AS runtime
COPY --from=build /out/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
EOF
2) Увімкніть QEMU та Buildx локально
QEMU дає можливість виконувати ARM-бінарники на x86_64 і навпаки. Buildx — інструмент Docker для мультиплатформених збірок.
# Установити binfmt з підтримкою кількох архітектур
sudo docker run --privileged --rm tonistiigi/binfmt --install all
# Створити та активувати builder з підтримкою BuildKit
docker buildx create --name multi --use
docker buildx inspect --bootstrap
3) Прогін тестів і multi-arch збірка локально
Спочатку ганяємо тести в емульованому середовищі, далі — збірка і публікація.
# Тести для amd64
docker buildx build --platform linux/amd64 --target test --progress=plain .
# Тести для arm64 (через QEMU)
docker buildx build --platform linux/arm64 --target test --progress=plain .
# Якщо все зелене — збираємо multi-arch образ і пушимо
export IMAGE=youruser/yourapp:latest
docker login -u "$DOCKERHUB_USER" -p "$DOCKERHUB_TOKEN"
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t "$IMAGE" \
--push \
.
docker buildx imagetools inspect "$IMAGE"
GitHub Actions: мультиплатформений CI
Далі — повноцінний CI. Будуть два завдання: тест-матриця (amd64/arm64) і релізна збірка з публікацією у реєстр. У Secrets додайте DOCKERHUB_USERNAME і DOCKERHUB_TOKEN. Це — чиста автоматизація задач без ручних дій 🐳
mkdir -p .github/workflows
cat > .github/workflows/ci.yml <<'EOF'
name: go-multiarch-ci
on:
push:
branches: [ main ]
pull_request:
jobs:
test:
name: Test (${{ matrix.platform }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform: [linux/amd64, linux/arm64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Go cache
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Run tests in container (${ { matrix.platform } })
run: |
docker buildx build \
--platform ${{ matrix.platform }} \
--target test \
--progress=plain \
.
build-and-push:
name: Build and Push (multi-arch)
needs: [test]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push multi-arch image
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: youruser/yourapp:latest
cache-from: type=registry,ref=youruser/yourapp:cache
cache-to: type=registry,ref=youruser/yourapp:cache,mode=max
EOF
Альтернативні способи
- Goreleaser: автоматизує збірку бінарників для різних GOOS/GOARCH, пакує архіви та релізи. Можна поєднати з Docker Buildx.
- GitLab CI/CircleCI: аналогічні пайплайни з runner'ами та QEMU.
- Native ARM runner: якщо є arm64 runner, тести й збірка будуть значно швидші, ніж під QEMU.
GUI-спосіб (де доречно)
- GitHub: відкрийте вкладку Actions у вашому репозиторії, оберіть Go Workflow, збережіть. Потім відредагуйте YAML, додавши кроки Buildx/QEMU (як вище).
- Docker Desktop for Linux: у налаштуваннях увімкніть BuildKit і перевірте, що підтримується buildx. Далі використовуйте інтегрований термінал для команд.
FAQ
Чому тести на arm64 повільні?
QEMU — це емуляція, вона повільніша. Варіанти: скоротити набір тестів на неосновних архітектурах, кешувати залежності, або додати реальний arm64 runner.
Отримую "exec format error"
Зазвичай це означає, що бінарник/образ не під ту архітектуру. Перевіряйте параметр --platform у buildx і manifest образу через docker buildx imagetools inspect.
CGO і нативні C-бібліотеки
Для cross-compilation з CGO потрібні крос-компілятори й заголовки. Налаштуйте CC і CXX (наприклад, aarch64-linux-gnu-gcc) у стадії збірки. Інакше встановіть CGO_ENABLED=0.
Приватні Go-модулі
Додайте GOPRIVATE і налаштуйте git credentials у CI. Наприклад, через git config url..insteadof або ssh-ключ у Secrets.
Як прискорити збірку?
Увімкніть BuildKit-кеш (cache-from/cache-to), кешуйте go build і модулі. Розбийте довгі RUN-команди та фіксуйте версії залежностей.
Проблеми з правами Docker у CI
На GitHub Actions використовуйте офіційні дії docker/*, вони вже працюють із правами. Локально — додайте себе в групу docker та перелогіньтесь.
Як тегувати релізи?
Використовуйте Git-теги і змінну GITHUB_REF для формування тегів образів: latest, vX.Y.Z. Додайте кроки у build-and-push.
Порада від Kernelka
Не запускайте інтеграційні тести всюди: робіть швидкі юніт-тести на всіх платформах, а важкі — лише на основній. Так ваш CI буде прудким і недорогим 😉
Підсумок
- QEMU + Docker Buildx забезпечують мультиплатформені тести та збірку.
- Окрема тест-стадія в Dockerfile зупиняє збірку при падінні тестів.
- GitHub Actions легко автоматизує тести й публікацію multi-arch образів.
- Кеш і мінімальні базові образи прискорюють CI і зменшують витрати.
- Плануйте матрицю платформ з урахуванням продуктивності QEMU.

Прокоментувати
На сайті відображається лише твоє ім'я та коментар. Електронна пошта зберігається виключно для зв'язку з тобою за потреби та в жодному разі не передається стороннім особам.