İçeriğe geç
Tüm yazılar

Go Uygulamalarını Docker ile Derleyin: Taşınabilir ve Hermetik Bir Araç Zinciri

Ghazi Triki tarafından · 9 dk okuma

Go uygulamalarını Docker ile derleme
Bu yazıda

Go’yu ana makinenize kurmayı bırakın. GOPATH kirliliği yok, “benim makinemde çalışıyor” bahanesi yok, sürüm kayması sıfır. BigBlueButton Learning Analytics raporları için Java ajanlarını yeniden yazarken ve güvenli Piler Go Agent’ı geliştirirken kullandığımız kalıbın ta kendisi bu. Yalnızca Docker ile statik ikili dosyaları nasıl teslim edebileceğinizi anlatıyoruz.

Yazan: Ghazi Triki, RIADVICE

“Go’yu kurmanız yeterli” yaklaşımının sorunu

BigBlueButton Learning Analytics raporları için Java tabanlı ajanları yönetirken klasik “bağımlılık cehennemi” ile karşı karşıya kaldık. Go’ya geçmek sadelik vaat ediyordu, ama yalnızca aynı hataları tekrarlamazsak. Ürettiği ikili dosyalar kadar hermetik bir derleme sürecine ihtiyacımız vardı.

Her ekip er ya da geç şu duvarlara çarpar:

  • Sürüm kayması. Ahmed 1.24’te, Omar 1.26’da, üretim sunucusu ise 1.25’te. Derleyicideki küçük bir değişiklik derlemeyi bozar, ama yalnızca Ahmed için.
  • Kirlenen ana makineler. Her iş istasyonunda farklı olan GOPATH, GOMODCACHE ve genel araç kurulumları (staticcheck, gofumpt).
  • Zorlu işe alışma süreci. Yeni bir mühendis ilk gününü ortam değişkenleri ve cgo için gereken C araç zincirleriyle boğuşarak geçirir.

RIADVICE’ta disipline ve düzene önem veriyoruz. Bunu yansıtan, yani temiz, öngörülebilir ve ortak bir derleme süreci istedik.

Standart yanıt “Docker kullanın” olur, ancak çoğu eğitim yalnızca bir kapsayıcı imajının nasıl derleneceğini gösterir. Go derleyicisini yerel olarak hiç kurmadan ana makinenizde düz, statik bağlanmış bir ikili dosyayı, yani bir systemd hizmeti ya da internetten yalıtılmış (air-gapped) bir dağıtım için gerçekten ihtiyaç duyduğunuz çıktıyı nasıl elde edeceğinizi göstermezler.

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

Resmi golang imajı derleyicinin ta kendisidir. Kaynak kodunuz /app dizinine bind mount ile bağlanır. İkili dosya, ana makinenizde dist/myapp konumuna yazılır. Komut tamamlandığında kapsayıcı yok edilir (--rm) ve ana makineniz önceki kadar temiz kalır.

Gerçek dünyadan deneyim: BigBlueButton’dan Piler’e

Bu yalnızca teori değil. Bu kalıbı iki kritik projede uyguladık:

  1. BigBlueButton Learning Analytics Reports: Ağır Java ajanlarını hafif Go ikili dosyalarına dönüştürdük. Docker tabanlı derlemeler sayesinde, o ortamı dizüstü bilgisayarlarımızda kurmamıza gerek kalmadan BBB sunucularının birebir Debian ortamını hedefleyebildik.
  2. Piler Go Agent: E-posta arşivleme çözümümüz için güvenliği sıkılaştırılmış bir ajan geliştirdik. Derleme sürecinin de kod kadar güvenli olması gerekiyordu. Derleyiciyi belirli bir SHA’ya sabitleyerek ikili dosyadaki her bitin hesabını verebildik.

Bu yöntem neden Go’yu kurmaktan daha iyi

KonuAna makinede go installdocker run golang:...
Go sürümüEn son hangisini kurduysanızSabitlenmiş, herkes için aynı
GOPATH / önbellek~/go dizinini kirletirHermetik kapsayıcı katmanları
cgo araç zinciriAna makinede kurulum gerektirirResmi imajla birlikte gelir
CI ile tutarlılık“Benim makinemde çalışıyor”Aynı imaj, aynı ikili dosya
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: Disiplinin Kaynağı

Derleme adımlarını kayıt altına almak için bir Makefile kullanıyoruz. GO_IMAGE değerinin belirli bir sürüme sabitlendiğine dikkat edin. latest etiketini asla kullanmayız.

Önemli teknik ayrıntılar

1. Statik ikili dosyalar için CGO_ENABLED=0

Piler ajanında, güncel bir Debian’dan eski bir sunucuya kadar her yerde çalışabilen ikili dosyalara ihtiyacımız vardı. CGO’yu devre dışı bırakmak, ikili dosyanın ihtiyaç duyduğu her şeyi içermesini ve ana makinedeki kütüphanelere hiçbir dinamik bağımlılığı olmamasını sağlar.

2. Köken bilgisi için -ldflags -X

İkili dosyanız size tam olarak nereden geldiğini söyleyebilmelidir. Git commit’ini ve derleme tarihini bağlama (link) aşamasında enjekte ediyoruz. Bu, onlarca farklı kümedeki BigBlueButton ajanlarında hata ayıklamak için hayati önem taşıyordu.

3. Derleyici imajını sabitlemek

Kültürümüzde tutarlılığa inanırız. latest yerine golang:1.26.5-trixie sürümünü sabitlemek, Ahmed ikili dosyayı bugün, Omar da altı ay sonra derlese bile çıktının bit düzeyinde birebir aynı olacağı anlamına gelir.

Sonuç

Derleyici bir araçtır ve her araç gibi yerinde durmalıdır. Go araç zincirini Docker’a taşıyarak “bende çalışıyor” türündeki hataların bütün bir sınıfını ortadan kaldırdık ve RIADVICE’a katılan her yeni mühendis için işe alışma sürecini sadeleştirdik.

İster Java ajanlarını yeniden yazıyor olun ister Piler için güvenli bir API geliştiriyor olun, bu kalıp üretim sistemlerinin gerektirdiği disiplini ve güvenilirliği sağlar.


Ghazi Triki, RIADVICE’ın kurucusudur. BigBlueButton, Piler ve daha fazlası için yüksek performanslı, güvenli entegrasyonlar geliştiriyoruz. Gelin, birlikte harika bir şey inşa edelim.

🔗 golang-docker-boilerplate deposunu GitHub’dan edinin

Bu yazıyı paylaşın