Ugrás a tartalomra
Minden cikk

Go-alkalmazások építése Dockerrel: hordozható, hermetikus eszközlánc

Szerző: Ghazi Triki · 9 perc olvasás

Go-alkalmazások építése Dockerrel
A cikk tartalma

Ne telepítse a Go-t a gépére. Nincs szennyezett GOPATH, nincs „nálam működik”, és nincs verziócsúszás. Pontosan ezt a mintát használtuk, amikor újraírtuk a BigBlueButton Learning Analytics jelentések Java-ügynökeit, és amikor megépítettük a biztonságos Piler Go Agentet. Megmutatjuk, hogyan szállíthat statikus binárisokat kizárólag Dockerrel.

Írta: Ghazi Triki, RIADVICE

Mi a gond a „csak telepítse a Go-t” megoldással

Amikor még Java-alapú ügynököket kezeltünk a BigBlueButton Learning Analytics jelentésekhez, a klasszikus „függőségi pokollal” szembesültünk. A Go-ra való átállás egyszerűséget ígért, de csak akkor, ha nem ismételjük meg ugyanazokat a hibákat. Olyan buildfolyamatra volt szükségünk, amely ugyanolyan hermetikus, mint az általa előállított binárisok.

Előbb-utóbb minden csapat ezekbe a falakba ütközik:

  • Verziócsúszás. Ahmed az 1.24-es, Omar az 1.26-os verziót használja, az éles szerveren pedig 1.25 fut. Egy apró fordítóváltozás elrontja a buildet, de csak Ahmednél.
  • Szennyezett gépek. GOPATH, GOMODCACHE és globálisan telepített eszközök (staticcheck, gofumpt), amelyek minden munkaállomáson mások.
  • Nehézkes betanulás. Egy új mérnök az első napját környezeti változókkal és a cgo C-eszközláncaival küszködve tölti.

A RIADVICE-nál fontos számunkra a fegyelem és a rend. Olyan buildfolyamatot akartunk, amely ezt tükrözi: tiszta, kiszámítható és közös.

A szokásos válasz az, hogy „használjon Dockert”, de a legtöbb oktatóanyag csak azt mutatja meg, hogyan építsen konténerképet. Azt nem, hogyan kaphat egyszerű, statikusan linkelt binárist a saját gépén anélkül, hogy valaha is helyben telepítené a Go-fordítót. Pedig valójában erre az összetevőre van szüksége egy systemd-szolgáltatáshoz vagy egy hálózattól elszigetelt telepítéshez.

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

A hivatalos golang kép maga a fordító. A forráskódja bind mounttal az /app útvonalra csatolódik. A bináris a gépén a dist/myapp helyre kerül. Amikor a parancs befejeződik, a konténer megsemmisül (--rm), és a gépe ugyanolyan tiszta marad, mint előtte.

Tapasztalatok a gyakorlatból: a BigBlueButtontól a Pilerig

Ez nem csupán elmélet. Két kritikus projektben alkalmaztuk ezt a mintát:

  1. BigBlueButton Learning Analytics Reports: A nehézkes Java-ügynököket könnyű Go-binárisokká írtuk át. A Docker-alapú buildekkel pontosan a BBB-szerverek Debian-környezetét célozhattuk meg anélkül, hogy erre a környezetre a laptopjainkon szükség lett volna.
  2. Piler Go Agent: E-mail-archiváló megoldásunkhoz biztonsági szempontból megerősített ügynököt építettünk. A buildfolyamatnak ugyanolyan biztonságosnak kellett lennie, mint a kódnak. Azzal, hogy a fordítót egy adott SHA-hoz rögzítettük, biztosítottuk, hogy a bináris minden bitje ellenőrizhető legyen.

Miért jobb ez, mint a Go telepítése

Szempontgo install a gépendocker run golang:...
Go-verzióAmit legutóbb telepítettRögzített, mindenkinél azonos
GOPATH / gyorsítótárSzennyezi a ~/go könyvtáratHermetikus konténerrétegek
cgo-eszközláncA gépen kell beállítaniA hivatalos kép tartalmazza
CI-egyezés„Nálam működik”Azonos kép, azonos bináris
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 ./...

A Makefile: a fegyelem forrása

A buildlépéseket egy Makefile rögzíti. Figyelje meg, hogy a GO_IMAGE egy konkrét verzióhoz van rögzítve. A latest címkét soha nem használjuk.

A lényeges technikai részletek

1. CGO_ENABLED=0 a statikus binárisokhoz

A Piler-ügynökhöz olyan binárisokra volt szükségünk, amelyek a modern Debiantól a régi szerverekig bármin futnak. A CGO kikapcsolása biztosítja, hogy a bináris mindent tartalmazzon, amire szüksége van, és ne függjön dinamikusan a gép könyvtáraitól.

2. -ldflags -X a származás igazolásához

A binárisnak pontosan meg kell tudnia mondani, honnan származik. A git-commitot és a build dátumát linkeléskor injektáljuk. Ez létfontosságú volt a BigBlueButton-ügynökök hibakereséséhez több tucat különböző klaszteren.

3. A fordítókép rögzítése

Kultúránkban a következetességben hiszünk. Ha a latest helyett a golang:1.26.5-trixie képet rögzítjük, akkor ha Ahmed ma építi meg a binárist, Omar pedig hat hónap múlva, a kimenet bitre pontosan azonos lesz.

Összegzés

A fordító eszköz, és mint minden eszköznek, ennek is megvan a maga helye. Azzal, hogy a Go-eszközláncot Dockerbe helyeztük át, a „nálam működik” típusú hibák egész osztályát szüntettük meg, és egyszerűbbé tettük a betanulást minden új mérnök számára, aki a RIADVICE-hoz csatlakozik.

Akár Java-ügynököket ír újra, akár biztonságos API-t épít a Pilerhez, ez a minta biztosítja az éles rendszerekhez szükséges fegyelmet és megbízhatóságot.


Ghazi Triki a RIADVICE alapítója. Nagy teljesítményű, biztonságos integrációkat építünk a BigBlueButtonhoz, a Pilerhez és más rendszerekhez. Építsünk együtt valami nagyszerűt.

🔗 A golang-docker-boilerplate a GitHubon