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)
- Go App
- Python App
# 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"]
# Stage 1: build — install deps into a prefix
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --prefix=/install -r requirements.txt
# Stage 2: runtime — copy only installed packages + app
FROM python:3.12-slim
COPY --from=builder /install /usr/local
WORKDIR /app
COPY src/ .
USER nobody
EXPOSE 8080
CMD ["python", "main.py"]
Gotcha: Never run as root in a container. Add
USER nonrootto your Dockerfile. If the container is compromised, root = host root on misconfigured systems.