Go

How do you cross-compile Go and produce a fully static binary for a scratch container?

Question 428MediumGo 1.22 to 1.25

The Go toolchain can cross-compile to every supported target: set GOOS/GOARCH (and GOARM/GOAMD64 for micro-architecture levels). cgo is disabled by default when cross-compiling, and since Go 1.20 also whenever no C compiler is found.

go tool dist list                         # all supported GOOS/GOARCH pairs
GOOS=linux GOARCH=arm64 go build -o bin/app ./cmd/app
GOOS=windows GOARCH=amd64 go build -o app.exe ./cmd/app

# static, reproducible, smaller:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 \
  go build -trimpath -ldflags="-s -w" -o app ./cmd/app

# Dockerfile final stage
FROM scratch
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=build /app /app
ENTRYPOINT ["/app"]

Gotchas for scratch images:

  • No CA certificates means TLS fails. Copy them, or import golang.org/x/crypto/x509roots/fallback.
  • No /usr/share/zoneinfo. Import time/tzdata or build with -tags timetzdata.
  • No /etc/passwd, so os/user lookups fail.
  • With cgo on, the binary links against glibc dynamically. Check with ldd/file.

Cross-compiling with cgo needs a cross C toolchain (CC=aarch64-linux-gnu-gcc) or zig cc.

More on Modules, Packages & Tooling

All 36 Modules, Packages & Tooling questions