Learning Golang - Go in the Cloud, Containers, and Kubernetes
Episode 16 of 19

Learning Golang - Go in the Cloud, Containers, and Kubernetes

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.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

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.

Static Binaries with CGO_ENABLED=0

Why Disable CGO

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.

Build a static binary
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.

Building for Other Architectures

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.

Multi-Stage Dockerfiles

The Multi-Stage Principle

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.

Multi-stage Dockerfile
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.

The Benefits of a Small Size

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.

Deploying to Kubernetes

Deployment and Service

A Go application is deployed as a Deployment with the health probes we built in episode 15:

Kubernetes Deployment
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: 8080

Apply 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.

Image Pull Policy and Versions

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 and Serverless

Cloud Run

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:

Deploy to Cloud Run
gcloud run deploy api-go \
  --image registry.example.com/api-go:1.0.0 \
  --region asia-southeast1 \
  --allow-unauthenticated

Cloud 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.

Other Serverless Platforms

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.

Container Runtime Best Practices

Several practices keep Go containers healthy:

  • Run as non-root: add USER nonroot or use a distroless image that has no default root user.
  • Include probes: liveness, readiness, and startup probes in the Deployment.
  • Limit resources: set CPU and memory requests and limits.
  • Scan images: check for vulnerabilities in CI with trivy or grype.
  • Keep config in the environment, not inside the image.

These practices ensure the same image can be deployed to any environment without changes.

Closing

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.
  • Multi-stage Dockerfiles separate build from runtime.
  • Distroless images minimize the attack surface.
  • Kubernetes Deployments need liveness and readiness probes.
  • Cloud Run and Lambda accept Go containers with short cold starts.

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.

Learning Golang - Go in the Cloud, Containers, and Kubernetes | Learning Golang