Frontend Labs
⋯

67. Running Go in containers and Kubernetes

67.1 Container image basics

FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -o /app ./cmd/server

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

scratch is smallest; distroless is often more convenient because it includes useful basics such as CA certificates and a non-root user variant. For cgo-heavy apps, use a runtime image that contains the required shared libraries.

67.2 Kubernetes probes and graceful shutdown

readinessProbe:
  httpGet:
    path: /readyz
    port: 8080
  periodSeconds: 5
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
terminationGracePeriodSeconds: 30

Your Go process should handle SIGTERM, stop accepting new work, let in-flight requests finish up to a deadline, and then exit. Kubernetes will send SIGKILL after terminationGracePeriodSeconds.

67.3 Resource limits and Go runtime settings

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "512Mi"
env:
  - name: GOMEMLIMIT
    value: "450MiB"

Set GOMEMLIMIT below the container memory limit so the runtime starts working harder before the kernel OOM-kills the process. Leave room for non-Go memory: stacks, mmap, cgo, kernel buffers, and the process itself.

67.4 Configuration and secrets

Use environment variables, mounted files, or a secret manager. Avoid baking environment-specific config into the binary or image.

type Config struct {
	Addr        string
	DatabaseURL string
	LogLevel    string
}

func LoadConfig() Config {
	return Config{
		Addr:        getenv("ADDR", ":8080"),
		DatabaseURL: os.Getenv("DATABASE_URL"),
		LogLevel:    getenv("LOG_LEVEL", "info"),
	}
}

Validate config at startup. A service should fail fast if required config is missing; partial startup with broken dependencies creates harder incidents.

67.5 Deployment checklist

  • Runs as non-root.
  • Handles SIGTERM gracefully.
  • Has readiness and liveness endpoints.
  • Uses explicit HTTP server timeouts.
  • Sets memory limits and, where useful, GOMEMLIMIT.
  • Exposes structured logs, metrics, and traces.
  • Does not log secrets.
  • Has pprof available only on an internal/admin path.
  • Includes build version/commit in logs and /version.
  • Has rollback instructions.

That's the full arc — from go build's hello-world loop in Part I to a capstone database engine, production-shippable service, and professional debugging/refactoring/operations workflow in Part VIII. What follows is reference material, not more reading: idioms, pitfalls, a glossary, and cheat sheets to check back against while you're actually writing Go. For structured day-by-day practice on top of this guide's theory, see the companion golang-90-day-plan.md.

Applied in the series: Linux guide, Chapters 74–76 (PID 1 and zombies, GOMAXPROCS, GOMEMLIMIT) and the TCP/IP guide's Kubernetes networking chapter (ndots:5, the conntrack DNS race).


Generated from real-life-golang-guide.md · 8 Oct 2026 16:36