Irbisa · Cheatsheet
Go in Production
Multi-stage Docker builds, config and secrets, graceful shutdown, health and readiness, GOMAXPROCS in containers, migrations
What is a container, how does it differ from a virtual machine, and what do namespaces and cgroups give it?
What do a Pod, a Deployment, a Service and a ConfigMap each do, and how does a Go service get from an image to receiving traffic in Kubernetes?
apiVersion: apps/v1kind: Deploymentmetadata: name: ordersspec: replicas: 3 # keep three Pods of this version running…How should a Go service get its configuration, what does the 12-factor app say about it, and what happens when a required value is missing?
type Config struct { Addr string DatabaseURL string // a secret: never log it ShutdownTimeout time.Duration}…What is the difference between
SIGTERM,SIGINTandSIGKILL, and which of them can a Go program catch?Why should a Go container run as a non-root user, and how do you set that up on
scratchor distroless?# Dockerfile: USER 65532:65532 (numeric, so runAsNonRoot can verify it)spec: securityContext: runAsNonRoot: true runAsUser: 65532 runAsGroup: 65532…The Alpine-based container starts via
entrypoint.sh, which reads a secret and runs/app/server. Pods now take the full 30 s to stop and never log a shutdown. Why?#!/bin/sh# entrypoint.shset -euDB_PASSWORD="$(cat /run/secrets/db-password)"export DB_PASSWORD…Why must secrets never be baked into a container image, and how should a Go service get them instead, at build time and at runtime?
# syntax=docker/dockerfile:1FROM golang:1.25 AS buildWORKDIR /srcENV GOPRIVATE=github.com/acme/*COPY go.mod go.sum ./# wrong: ARG GITHUB_TOKEN, then RUN git config ... $GITHUB_TOKEN…What does
-ldflags="-s -w"strip from a Go binary, and what still works afterwards: panic traces,pprof, Delve?Find the bug in this graceful shutdown: on
SIGTERM, requests that are in flight still get cut off.func run(h http.Handler, db *sql.DB) error { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM) defer stop() srv := &http.Server{Addr: ":8080", Handler: h, ReadHeaderTimeout: 5 * time.Second} go func() { <-ctx.Done() sctx, cancel := context.WithTimeout(context.Background(), 25*time.Second) defer cancel() srv.Shutdown(sctx) }() if err := srv.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { return err } return db.Close()}Find the bug: pods are killed with exit code 137 in the middle of a rolling update, and the
Shutdowndrain never finishes.spec: terminationGracePeriodSeconds: 30 containers: - name: api image: registry.example.com/api:1.5.0 env: - name: SHUTDOWN_TIMEOUT # the context deadline passed to srv.Shutdown value: "25s" lifecycle: preStop: sleep: seconds: 30 # wait until the load balancer stops sending trafficHow do you expose
pprofon a production service safely, and what can an attacker do with an open/debug/pprof/?import "net/http/pprof" // its init also registers on http.DefaultServeMux func adminServer() *http.Server { mux := http.NewServeMux() mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/profile", pprof.Profile)…A pod restarts with
OOMKilledand exit code 137, and the Go logs show nothing. What happened, and how is that different from a Goout of memorycrash?How does the Horizontal Pod Autoscaler decide how many pods to run, and why is CPU a poor scaling signal for an I/O-bound Go API or a Kafka consumer?
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: apispec: scaleTargetRef:…What should the CI pipeline of a Go service run, in what order, and what keeps it fast (module and build caches, test sharding)?
on: pull_request: push: branches: [main]jobs: checks: # seconds: fail before anything slow starts…What is the difference between rolling, blue-green and canary deployments, and what must a Go service support for any of them to have zero downtime?
Should database migrations run when the service starts or as a separate step of the deploy, and what goes wrong with each?
Ten replicas each run the same hourly
time.Tickerjob, so the report goes out ten times. How do you run periodic work exactly once?// Every replica ticks once a minute and calls hourly. The first one to claim// the hour runs the job; the other nine see the claim and skip.func hourly(ctx context.Context, db *sql.DB, job string, run func(context.Context, time.Time) error) error { period := time.Now().UTC().Truncate(time.Hour) // the run's identity: "the 13:00 report" res, err := db.ExecContext(ctx, ` INSERT INTO job_runs (job, period) VALUES ($1, $2)…How does readiness gate a rolling update, and how do you make a broken release stop after its first pods instead of replacing the whole fleet?
apiVersion: apps/v1kind: Deploymentmetadata: name: apispec: replicas: 10…Behind a load balancer, a Go service causes rare
502s at any load, and none of them appear in its own logs. How canIdleTimeoutcause this, and what is the fix?How do you set CPU and memory requests and limits for a Go service in Kubernetes, and what happens to
GOMAXPROCSandGOMEMLIMITif you drop the CPU limit?containers: - name: api image: registry.example.com/api:1.5.0 resources: requests: cpu: "2"…A service runs an HTTP API, a Kafka consumer, background workers and a DB pool. On
SIGTERM, in what order do you shut them down, and why?// Shutdown(ctx) stops taking new work and waits for work already taken.type drainer interface{ Shutdown(ctx context.Context) error } func drain(srv *http.Server, consumer, workers, producer, telemetry drainer, db *sql.DB) error { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel()…