Skip to main content

Containers & Docker — Package Once, Run Anywhere

Package your app and all its dependencies into an isolated, reproducible unit — same image runs in dev, CI, and prod.

When to use

  • Always for production workloads
  • Multi-stage builds for compiled languages (Go, Java) — separate build and runtime stages

Tradeoffs

  • Image bloat if you copy unnecessary files or use fat base images
  • Secrets embedded in image layers are permanently exposed (even if deleted in a later layer)
# Stage 1: build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server

# Stage 2: runtime — minimal image, no compiler
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/server"]

Gotcha: Never run as root in a container. Add USER nonroot to your Dockerfile. If the container is compromised, root = host root on misconfigured systems.