Skip to content

@tank/docker-production-patterns

1.0.0

Description

Production Docker patterns covering Dockerfiles, multi-stage builds, BuildKit, security hardening, Compose production usage, lifecycle/signals, logging, and CI/CD.

Triggered by

Dockerfiledocker productionBuildKitdocker securityhealth checkdistroless
Download
Unsafe
tank install @tank/docker-production-patterns

Docker Production Patterns

Core Philosophy

  1. Ship the minimum viable image — Every unnecessary binary, library, and shell in the final image is attack surface and wasted bandwidth. Multi-stage builds exist to separate build-time from run-time.
  2. Layers are the caching unit — Order instructions from least-changing (base image, system deps) to most-changing (application code). A single misordered COPY invalidates every subsequent layer.
  3. Containers are ephemeral — Design for termination. Handle SIGTERM, drain connections, flush buffers. If your container cannot stop cleanly in 10 seconds, the architecture is wrong.
  4. Security is not optional — Run as non-root, use read-only filesystems, scan images in CI, never bake secrets into layers. The default Docker setup is insecure for production.
  5. Compose is not just for dev — With profiles, resource limits, health checks, and secrets, Compose serves single-host production. Know when to graduate to orchestrators.

Quick-Start: Common Problems

"My Docker image is too large"

  1. Switch to multi-stage build — separate builder from runtime
  2. Use minimal base: *-slim, *-alpine, or distroless
  3. Audit .dockerignore — exclude node_modules/, .git/, tests, docs
  4. Combine RUN commands to reduce layers; clean package caches in same layer
  5. Copy only production artifacts into the final stage -> See references/dockerfile-patterns.md

"Builds are slow in CI"

  1. Enable BuildKit (DOCKER_BUILDKIT=1)
  2. Use --mount=type=cache for package manager caches (npm, pip, go mod)
  3. Order COPY instructions: lockfile first, install, then source code
  4. Export/import cache with --cache-to and --cache-from in CI -> See references/buildkit-optimization.md

"How do I handle secrets during build?"

  1. Use BuildKit secret mounts: --mount=type=secret,id=mykey
  2. Pass at build time: docker build --secret id=mykey,src=./key.pem
  3. Never use ARG or ENV for secrets — they persist in image layers -> See references/buildkit-optimization.md and references/security-hardening.md

"Container ignores SIGTERM / takes 10s to stop"

  1. Use exec form for ENTRYPOINT: ["node", "server.js"] not node server.js
  2. Ensure your process is PID 1 (or use --init / tini)
  3. Register a SIGTERM handler in your application code -> See references/lifecycle-signals.md

"How do I run Compose in production?"

  1. Use override files: docker-compose.yml (base) + docker-compose.prod.yml
  2. Set resource limits (memory, CPU), restart policies, health checks
  3. Use docker compose --profile prod up for environment-specific services
  4. Manage secrets via Compose secrets, not environment variables -> See references/compose-production.md

Decision Trees

Base Image Selection

RequirementBase Image
Smallest size, maximum securityDistroless (gcr.io/distroless) or scratch
Need shell for debugging*-slim variants (debian-slim, python-slim)
Alpine ecosystem / musl acceptable*-alpine (watch for DNS/musl issues)
Enterprise compliance / supportDocker Official Images, Chainguard
Widest compatibilityDefault Debian-based tags

When to Graduate from Compose

SignalRecommendation
Single host, < 10 servicesDocker Compose is fine
Multi-host, high availability neededKubernetes or Docker Swarm
Auto-scaling requiredKubernetes
Rolling updates with zero downtimeKubernetes or Swarm
Simple deploy, one serverCompose + systemd

Image Tagging Strategy

TagPurposeMutable?
v1.2.3Release artifact, immutable referenceNo
sha-abc1234Git SHA, CI traceabilityNo
latestConvenience for dev, never for production deploysYes
mainLatest from default branchYes

Language-Specific Quick Reference

LanguageBase (build)Base (runtime)Key gotcha
Node.jsnode:22-slimnode:22-slim or distrolessCopy package*.json first, npm ci --omit=dev
Pythonpython:3.12-slimpython:3.12-slimUse --mount=type=cache,target=/root/.cache/pip
Gogolang:1.23scratch or distrolessCGO_ENABLED=0 for static binary
Rustrust:1.82debian:bookworm-slim or distrolessUse cargo-chef for dependency caching
Javaeclipse-temurin:21-jdkeclipse-temurin:21-jre-alpineUse jlink for custom minimal JRE

-> See references/dockerfile-patterns.md for complete Dockerfiles per language.

Reference Index

FileContents
references/dockerfile-patterns.mdMulti-stage builds, layer ordering, ENTRYPOINT vs CMD, base image selection, .dockerignore patterns, language-specific production Dockerfiles (Node.js, Python, Go, Rust, Java)
references/buildkit-optimization.mdBuildKit cache mounts, build secrets, SSH forwarding, multi-platform builds, cache export/import, CI cache backends, build arguments
references/security-hardening.mdNon-root users, distroless and minimal images, read-only filesystems, image scanning (Trivy, Grype, Snyk), secrets management, CIS benchmark essentials
references/compose-production.mdCompose v2 production configuration, profiles, service dependencies, override files, secrets, resource limits, networking, environment management
references/lifecycle-signals.mdPID 1 problem, SIGTERM/SIGKILL handling, tini and dumb-init, exec form vs shell form, health checks, restart policies, graceful shutdown patterns per language
references/logging-observability.mdLog drivers (json-file, fluentd, syslog), log rotation, structured logging, resource limits (CPU/memory/pids), monitoring patterns, OOM behavior
references/cicd-registry.mdGitHub Actions Docker builds, docker/metadata-action tagging, registry management (Docker Hub, GHCR, ECR), multi-arch builds, layer caching in CI, image promotion workflows

Command Palette

Search skills, docs, and navigate Tank