This episode takes a Go application to production: building a static binary with CGO_ENABLED=0, an efficient multi-stage Dockerfile, a minimal distroless image, plus deployment to Kubernetes, Cloud Run, and serverless platforms.

In episode 1 you heard that Go produces static binaries. Episode 16 is when you reap that benefit: Go applications are among the best candidates for containers because their images can be very small, secure, and quick to deploy.
Episode 16 takes a Go application to the cloud: building a static binary, assembling an efficient multi-stage Dockerfile, using a minimal distroless image, and deploying to Kubernetes, Cloud Run, and serverless platforms. By the end of the episode, your application runs in production with the smallest possible footprint.
CGO lets Go call C code, but it makes the binary depend on C libraries at runtime. Disabling it with CGO_ENABLED=0 produces a pure binary that runs in the smallest containers — including distroless and scratch, which have no shell.
CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o app .The -ldflags="-s -w" flag strips the symbol table and debug information, shrinking the binary size. To verify the result, file app should show statically linked.
Go supports cross-compilation without extra toolchains. GOOS and GOARCH determine the target: GOOS=linux GOARCH=arm64 for ARM, GOOS=darwin for macOS. This flexibility is what makes Go excel in multi-platform ecosystems.
A multi-stage Dockerfile separates the build environment from the runtime. The first stage uses a full Go image for compilation; the second stage copies only the binary — no source code and no toolchain.
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app .
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/app /app/app
ENTRYPOINT ["/app/app"]The builder stage downloads dependencies once via go mod download, taking advantage of layer caching. The distroless image contains only the binary and a minimal runtime — no shell, no package manager, and a very small attack surface.
A good Go image is a few tens of megabytes, far smaller than Python- or Node-based images. The benefits: faster downloads at deployment time, more economical registry storage, and faster container startup — all crucial for rapid scaling.
A Go application is deployed as a Deployment with the health probes we built in episode 15:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-go
spec:
replicas: 3
selector:
matchLabels:
app: api-go
template:
metadata:
labels:
app: api-go
spec:
containers:
- name: api-go
image: registry.example.com/api-go:1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /readyz
port: 8080Apply it with kubectl apply -f deployment.yaml, then expose it through a Service and Ingress. A HorizontalPodAutoscaler can add replicas based on CPU metrics or requests per second.
Always tag images with a unique version — not latest in production, because it's hard to roll back. imagePullPolicy: IfNotPresent speeds up redeploys, while a changing tag triggers a new image pull.
Cloud Run runs containers without needing to manage a cluster. Static Go images are a great fit because of their short cold start. Deploy with the command:
gcloud run deploy api-go \
--image registry.example.com/api-go:1.0.0 \
--region asia-southeast1 \
--allow-unauthenticatedCloud Run scales to zero when there's no traffic, so you only pay when the service is used. The port the application listens on is read from the PORT environment variable.
AWS Lambda supports Go through custom runtimes or container images, and so do Google Cloud Functions and Azure Functions. A static Go binary can be packaged as a function container image without any extra runtime, so its memory footprint is far smaller than other languages.
Several practices keep Go containers healthy:
USER nonroot or use a distroless image that has no default root user.requests and limits.These practices ensure the same image can be deployed to any environment without changes.
Episode 16 took a Go application to production: building a static binary with CGO_ENABLED=0 and -ldflags, a multi-stage Dockerfile with a minimal distroless image, deploying to Kubernetes with probes, and deploying to Cloud Run and serverless platforms.
Key takeaways:
CGO_ENABLED=0 produces a static binary with no C dependencies.-ldflags="-s -w" shrinks the binary size.In the next episode we will discuss CI/CD, release, and dependency management — automated build and test pipelines with GitHub Actions, keeping dependencies safe with go mod verify and govulncheck, plus a release workflow with versioning, semantic imports, and binary distribution.