Перейти до вмісту
Усі статті

Збирання застосунків Go за допомогою Docker: портативний герметичний інструментарій

автор: Ghazi Triki · 9 хв читання

Збирання застосунків Go за допомогою Docker
У цій статті

Не встановлюйте Go на хост. Жодного засмічення GOPATH, жодного «у мене все працює» і нульовий дрейф версій. Саме за цим шаблоном ми переписали Java-агенти для звітів BigBlueButton Learning Analytics і створили захищений Piler Go Agent. Ось як постачати статичні бінарні файли, використовуючи лише Docker.

Автор: Ghazi Triki, RIADVICE

Проблема підходу «просто встановіть Go»

Коли ми підтримували агенти на Java для звітів BigBlueButton Learning Analytics, ми зіткнулися з класичним «пеклом залежностей». Перехід на Go обіцяв простоту, але лише за умови, що ми не повторимо тих самих помилок. Нам був потрібен процес збирання, такий самий герметичний, як і бінарні файли, які він створює.

Рано чи пізно кожна команда натрапляє на ці перешкоди:

  • Дрейф версій. Ahmed працює з версією 1.24, Omar з 1.26, а робочий сервер з 1.25. Невелика зміна в компіляторі ламає збирання, але тільки в Ahmed.
  • Засмічені хости. GOPATH, GOMODCACHE і глобально встановлені інструменти (staticcheck, gofumpt), які відрізняються на кожній робочій станції.
  • Складний старт для новачків. Новий інженер витрачає перший день на боротьбу зі змінними середовища та інструментаріями C для cgo.

У RIADVICE ми цінуємо дисципліну й порядок. Ми хотіли процес збирання, який би це відображав: чистий, передбачуваний і спільний для всіх.

Стандартна відповідь звучить як «використовуйте Docker», але більшість посібників показують лише, як зібрати образ контейнера. Вони не пояснюють, як отримати звичайний статично скомпонований бінарний файл на хості, тобто той артефакт, який вам справді потрібен для служби systemd або розгортання в ізольованому від мережі середовищі, жодного разу не встановлюючи компілятор Go локально.

Shell
docker run --rm -v "$(pwd):/app" -w /app golang:1.26.5-trixie \
    go build -o dist/myapp ./cmd/myapp

Офіційний образ golang і є компілятором. Ваш вихідний код змонтовано в /app. Бінарний файл записується в dist/myapp на вашому хості. Щойно команда завершується, контейнер знищується (--rm), і хост залишається таким самим чистим, як і раніше.

Практичний досвід: від BigBlueButton до Piler

Це не лише теорія. Ми застосували цей шаблон у двох критично важливих проєктах:

  1. Звіти BigBlueButton Learning Analytics: ми переписали важкі агенти на Java на легкі бінарні файли Go. Збирання на основі Docker дало змогу орієнтуватися саме на те середовище Debian, що й на серверах BBB, не маючи цього середовища на наших ноутбуках.
  2. Piler Go Agent: для нашого рішення з архівування електронної пошти ми створили агент з посиленим захистом. Процес збирання мав бути таким самим безпечним, як і код. Закріпивши компілятор за конкретним SHA, ми гарантували, що кожен біт у бінарному файлі має відоме походження.

Чому це краще, ніж установлення Go

Аспектgo install на хостіdocker run golang:...
Версія GoТа, яку ви встановили останньоюЗакріплена, однакова для всіх
GOPATH / кешЗасмічує ~/goГерметичні шари контейнера
Інструментарій cgoПотребує налаштування хостаВходить до офіційного образу
Відповідність CI«У мене все працює»Той самий образ, той самий бінарний файл
Makefile
BINARY := mini-api
DIST := dist

# Version metadata derived from git
VERSION    := $(shell tmp=$$(git describe --tags --always --dirty 2>/dev/null) && echo "$${tmp#v}" || echo dev)
COMMIT     := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
BRANCH     := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)
BUILD_DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -X example.com/mini-api/internal/version.Version=$(VERSION) \
           -X example.com/mini-api/internal/version.Commit=$(COMMIT) \
           -X example.com/mini-api/internal/version.Branch=$(BRANCH) \
           -X example.com/mini-api/internal/version.BuildDate=$(BUILD_DATE)

# Pinned toolchain image
GO_IMAGE := golang:1.26.5-trixie

# Run any command inside the Go toolchain container
define run_in_docker
    docker run --rm -v "$(PWD):/app" -w /app $(GO_IMAGE)
endef

.PHONY: build test lint

build:
    @mkdir -p $(DIST)
    $(call run_in_docker) bash -c 'CGO_ENABLED=0 go build -buildvcs=false -ldflags="$(LDFLAGS)" -o $(DIST)/$(BINARY) ./cmd/$(BINARY)'
    @echo "Built $(DIST)/$(BINARY) (version $(VERSION))"

test:
    $(call run_in_docker) go test -race ./...

lint:
    $(call run_in_docker) go vet ./...

Makefile: джерело дисципліни

Ми використовуємо Makefile, щоб закріпити кроки збирання в коді. Зверніть увагу: GO_IMAGE закріплено за конкретною версією. Ми ніколи не використовуємо latest.

Технічні деталі, які мають значення

1. CGO_ENABLED=0 для статичних бінарних файлів

Для агента Piler нам були потрібні бінарні файли, які працюватимуть будь-де, від сучасного Debian до застарілого сервера. Вимкнення CGO гарантує, що бінарний файл містить усе необхідне і не має динамічних залежностей від бібліотек хоста.

2. -ldflags -X для відстеження походження

Бінарний файл має вміти точно сказати, звідки він узявся. Ми вбудовуємо git-коміт і дату збирання на етапі компонування. Це було надзвичайно важливо для налагодження агентів BigBlueButton у десятках різних кластерів.

3. Закріплення образу компілятора

Наша культура ґрунтується на послідовності. Закріплення golang:1.26.5-trixie замість latest означає, що коли Ahmed збирає бінарний файл сьогодні, а Omar через пів року, результат буде ідентичним до біта.

Висновок

Компілятор це інструмент, і, як будь-який інструмент, він має бути на своєму місці. Перенісши інструментарій Go у Docker, ми позбулися цілого класу помилок на кшталт «у мене працює» і спростили адаптацію кожного нового інженера, який приєднується до RIADVICE.

Переписуєте ви агенти на Java чи створюєте захищений API для Piler, цей шаблон забезпечує дисципліну й надійність, необхідні для робочих систем.


Ghazi Triki, засновник RIADVICE. Ми створюємо високопродуктивні та захищені інтеграції для BigBlueButton, Piler та інших систем. Створімо разом щось видатне.

🔗 Отримати golang-docker-boilerplate на GitHub

Поділитися статтею

  • Загальнодоступна версія ZcaleRight 1.0.0
    BigBlueButton · 5 хв читання

    ZcaleRight 1.0.0: десять серверів працюють так само просто, як один

    ZcaleRight розміщує зустрічі BigBlueButton у робочому середовищі з 2019 року. Тепер він досягає версії 1.0.0 і стає загальнодоступним: усі 69 можливостей опубліковано відкрито, повний посібник усередині продукту, угода про рівень обслуговування і власний сайт.

  • Open Source · 9 хв читання

    Вийшов Sukarix 0.4.0: високопродуктивні черги Redis для реальних високонавантажених конвеєрів

    Атомарне виконання Lua, вбудована дедуплікація за членством, структурована телеметрія прогресу та сувора ін’єкція залежностей: як Sukarix 0.4.0 дає корпоративну потужність без роздутого фреймворку і як він забезпечує роботу нашого конвеєра BigBlueButton Analytics у реальному часі.

  • Від семи років до семи днів
    Education · 5 хв читання

    Від 7 років до 7 днів з агентним ШІ

    Якщо ви колись бачили, як таблиця COCOMO II прогнозує 33 календарні місяці для проєкту, який ваша команда випустила за два спринти, ви вже знаєте проблему: моделі оцінювання було відкалібровано для світу, якого більше не існує.