Lewati ke konten
Semua artikel

Membangun Aplikasi Go dengan Docker: Toolchain yang Portabel dan Hermetis

oleh Ghazi Triki · 9 menit baca

Membangun aplikasi Go dengan Docker
Dalam artikel ini

Berhenti memasang Go di host Anda. Tanpa GOPATH yang tercemar, tanpa "di mesin saya jalan", dan tanpa selisih versi. Pola inilah yang kami gunakan untuk menulis ulang agen Java untuk laporan BigBlueButton Learning Analytics dan membangun Piler Go Agent yang aman. Berikut cara mengirimkan biner statis hanya dengan Docker.

Oleh Ghazi Triki, RIADVICE

Masalah dengan "pasang Go saja"

Saat mengelola agen berbasis Java untuk laporan BigBlueButton Learning Analytics, kami menghadapi "neraka dependensi" yang klasik. Beralih ke Go menjanjikan kesederhanaan, tetapi hanya jika kami tidak mengulangi kesalahan yang sama. Kami membutuhkan proses build yang sama hermetisnya dengan biner yang dihasilkannya.

Cepat atau lambat, setiap tim akan menghadapi tembok-tembok berikut:

  • Selisih versi. Ahmed memakai 1.24, Omar memakai 1.26, dan server produksi memakai 1.25. Perubahan kecil pada compiler merusak build, tetapi hanya di mesin Ahmed.
  • Host yang tercemar. GOPATH, GOMODCACHE, dan alat yang dipasang secara global (staticcheck, gofumpt) berbeda di setiap workstation.
  • Hambatan orientasi. Insinyur baru menghabiskan hari pertamanya bergulat dengan variabel lingkungan dan toolchain C untuk cgo.

Di RIADVICE, kami menjunjung disiplin dan keteraturan. Kami menginginkan proses build yang mencerminkan hal itu: bersih, dapat diprediksi, dan digunakan bersama.

Jawaban standarnya adalah "gunakan Docker", tetapi kebanyakan tutorial hanya menunjukkan cara membangun image kontainer. Tutorial itu tidak menunjukkan cara mendapatkan biner biasa yang di-link secara statis di host Anda, yaitu artefak yang sebenarnya Anda butuhkan untuk layanan systemd atau penerapan air-gapped, tanpa pernah memasang compiler Go secara lokal.

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

Image resmi golang berperan sebagai compiler. Kode sumber Anda di-bind-mount di /app. Biner ditulis ke dist/myapp di host Anda. Setelah perintah selesai, kontainer dihapus (--rm), dan host Anda tetap sebersih sebelumnya.

Pengalaman nyata: dari BigBlueButton hingga Piler

Ini bukan sekadar teori. Kami menerapkan pola ini pada dua proyek penting:

  1. BigBlueButton Learning Analytics Reports: Kami menulis ulang agen Java yang berat menjadi biner Go yang ringan. Build berbasis Docker memungkinkan kami menargetkan lingkungan Debian yang persis sama dengan server BBB tanpa perlu memiliki lingkungan itu di laptop kami.
  2. Piler Go Agent: Untuk solusi pengarsipan email kami, kami membangun agen yang diperkuat dari sisi keamanan. Proses build-nya harus seaman kodenya. Dengan mengunci compiler pada SHA tertentu, kami memastikan setiap bit dalam biner dapat dipertanggungjawabkan.

Mengapa cara ini lebih baik daripada memasang Go

Aspekgo install di hostdocker run golang:...
Versi GoVersi apa pun yang terakhir dipasangDikunci, identik untuk semua orang
GOPATH / cacheMencemari ~/goLapisan kontainer yang hermetis
Toolchain cgoPerlu disiapkan di hostSudah tersedia di image resmi
Kesamaan CI"Di mesin saya jalan"Image identik, biner identik
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: sumber disiplin

Kami menggunakan Makefile untuk membakukan langkah-langkah build. Perhatikan bahwa GO_IMAGE dikunci pada versi tertentu. Kami tidak pernah menggunakan latest.

Detail teknis yang penting

1. CGO_ENABLED=0 untuk biner statis

Pada agen Piler, kami membutuhkan biner yang dapat berjalan di mana saja, mulai dari Debian modern hingga server lawas. Menonaktifkan CGO memastikan biner berisi semua yang dibutuhkannya, tanpa dependensi dinamis pada pustaka host.

2. -ldflags -X untuk asal-usul build

Biner Anda harus dapat memberi tahu dengan tepat dari mana asalnya. Kami menyisipkan commit git dan tanggal build pada saat linking. Hal ini sangat penting untuk melakukan debugging agen BigBlueButton di puluhan klaster yang berbeda.

3. Mengunci image compiler

Dalam budaya kami, konsistensi adalah prinsip. Mengunci golang:1.26.5-trixie alih-alih menggunakan latest berarti jika Ahmed membangun biner hari ini dan Omar membangunnya enam bulan lagi, hasilnya identik hingga ke tingkat bit.

Kesimpulan

Compiler adalah alat, dan seperti alat lainnya, ia harus ditempatkan pada tempatnya. Dengan memindahkan toolchain Go ke dalam Docker, kami telah menghilangkan seluruh golongan bug "di mesin saya jalan" dan menyederhanakan orientasi bagi setiap insinyur baru yang bergabung dengan RIADVICE.

Baik Anda sedang menulis ulang agen Java maupun membangun API yang aman untuk Piler, pola ini memberikan disiplin dan keandalan yang dibutuhkan sistem produksi.


Ghazi Triki adalah pendiri RIADVICE. Kami membangun integrasi berkinerja tinggi dan aman untuk BigBlueButton, Piler, dan lainnya. Mari bangun sesuatu yang hebat bersama.

🔗 Dapatkan golang-docker-boilerplate di GitHub

Bagikan artikel ini