Go

How do you build a minimal, secure Docker image for a Go service (multi-stage build, scratch/distroless, CGO_ENABLED=0, CA certs, time zone data)?

Question 571MediumGo 1.22 to 1.25

Compile in a full Go image, then copy only the static binary into a tiny runtime image. CGO_ENABLED=0 produces a fully static binary with no libc dependency. Without it, the pure-Go net and os/user code is not guaranteed and the binary may not run on scratch.

# syntax=docker/dockerfile:1
FROM golang:1.25 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
    CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/app ./cmd/api

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app"]

Distroless static already includes CA certificates, /etc/passwd with a nonroot user, and tzdata. With scratch you must copy these in yourself: COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/. Without them, every outbound HTTPS call fails with "x509: certificate signed by unknown authority".

For time zones, you can embed the database in the binary with import _ "time/tzdata" or -tags timetzdata (about 450 KB). Otherwise time.LoadLocation("Europe/Berlin") fails on scratch.

Hardening:

  • Run as non-root with a read-only root filesystem.
  • Pin base images by digest.
  • Scan with govulncheck and an image scanner.
  • -trimpath removes local paths from the binary for reproducible builds.
  • Build info is kept, so go version -m app still lists module versions.

Gotcha: -s -w strips symbols, which makes core dumps harder to analyze. Keep an unstripped build artifact. Since Go 1.25, GOMAXPROCS respects the container's cgroup CPU limit automatically, so older code that sets it by hand (for example with automaxprocs) can drop that.

More on Observability, Debugging & Production Operations

All 14 Observability, Debugging & Production Operations questions