← Back to the course home

⏮️ Before & trade-offs

Every tool replaced something worse — and is itself the wrong tool somewhere. For each big idea in this course: what life was like before it, its honest merits ✅ and demerits ❌, and where to use it 👍 vs where not 👎.

🍱 Containers (Docker) — lessons 01–04

⏮️ Before containers

The server-room era: one app per physical machine, installed by hand from a wiki page — each server a unique "snowflake" nobody dared touch. Then virtual machines (~2000s): better packing, but every VM ships an entire OS — gigabytes on disk, minutes to boot, and the inside still drifted ("works on my VM"). Shipping software meant install docs, dependency checklists, and prayers. Docker (2013) made the lunchbox cheap: isolation without the whole OS.

✅ Merits

  • identical on every machine — dev = prod
  • starts in milliseconds, weighs MBs not GBs
  • many per machine (density = cheaper)
  • image = versioned, shippable artifact

❌ Demerits

  • shares the host kernel → weaker isolation than a VM
  • Linux-first (Mac/Windows secretly run a VM)
  • one more layer to learn and debug
  • images rot if base layers aren't rebuilt/patched

👍 Use when

  • web services, APIs, workers — anything server-side
  • CI needs a clean, repeatable environment
  • you're heading to Kubernetes/ECS (containers required)

👎 Think twice when

  • desktop/GUI apps — wrong tool entirely
  • running untrusted tenant code → use VMs/microVMs
  • needs kernel modules or exotic drivers
  • a static site — object storage hosting is simpler

Diagram ↗

🏬 Images & registries — lessons 02, 09

⏮️ Before image registries

Deploys were file transfers: rsync/FTP the code to each server, or bake "golden" VM snapshots/AMIs — slow to build, impossible to diff, mysterious to audit. "Which version is on server 7?" had no good answer. Registries turned deployment artifacts into versioned, fingerprinted, pull-from-anywhere objects.

✅ Merits

  • immutable, versioned artifacts (tags + digests)
  • layer dedup → pushes/pulls move only what changed
  • one source, any number of pullers
  • digests are tamper-proof fingerprints

❌ Demerits

  • registry down = deploys down (it's critical infra)
  • storage grows silently — needs a janitor (lesson 11)
  • tag mutability can lie unless you forbid it

👍 Use when

  • more than one machine ever runs the app
  • any CI/CD pipeline exists
  • Kubernetes (non-negotiable — it only pulls)

👎 Think twice when

  • pure serverless zips (Lambda zip → no image needed)
  • single-laptop experiments — local images are fine

Diagram ↗

🍽️ Docker Compose — lesson 06

⏮️ Before Compose

A README with twelve "now run this" commands, per-developer shell scripts, and laptops that each worked slightly differently. Or Vagrant VMs: better, but heavyweight and slow. Compose made the whole dev stack one reviewable file and one command.

✅ Merits

  • whole stack = one file in git, reviewable
  • one command up, one command down
  • identical across every teammate's laptop
  • gentle on-ramp to Kubernetes concepts

❌ Demerits

  • single machine only — no multi-node, no HA
  • no self-healing or autoscaling
  • depends_on = start order, NOT readiness

👍 Use when

  • local development (its true home)
  • demos, integration tests in CI
  • small apps on ONE server where downtime is okay

👎 Think twice when

  • production with real uptime needs → k8s/ECS
  • anything multi-node or auto-scaling
  • as a "cheap k8s" — it will grow teeth later

Diagram ↗

👨‍🍳 Multi-stage builds — lesson 07

⏮️ Before multi-stage (added to Docker in 2017)

Either you built on the host and COPY'd artifacts in (host drift — the exact disease containers cure), or you kept two Dockerfiles + a glue script (the old "builder pattern"), or you just shipped the kitchen: 1GB+ production images with compilers, package managers and source code inside.

✅ Merits

  • tiny final images (10–20× smaller is routine)
  • no build tools in prod → far fewer CVEs
  • one file, fully reproducible

❌ Demerits

  • debugging intermediate stages takes practice
  • CI cache needs care (--cache-from) or builds slow down

👍 Use when

  • anything with a build step: npm build, Go, Java, Rust
  • image size or scan reports hurt

👎 Think twice when

  • there's nothing to build — our zero-dep server.js is happily single-stage; stages for ceremony help nobody

Diagram ↗

🏦 AWS ECR — lessons 10–12

⏮️ Before ECR (2015)

Either Docker Hub for everything (public by default, rate-limited, passwords on every node), or self-hosting registry:2 — meaning YOU patch it, scale it, store it, back it up and secure it. On AWS, that was a lot of undifferentiated pain next to the compute you already ran.

✅ Merits

  • IAM auth — EKS nodes pull with a role, zero passwords
  • scan-on-push, immutable tags, lifecycle janitor built in
  • same-region pulls: fast + no egress surprise
  • pennies at small scale, zero servers to run

❌ Demerits

  • AWS-only; addresses are account- and region-bound
  • 12-hour token dance for humans (fine for CI)
  • cross-account sharing takes policy work

👍 Use when

  • your workloads run on AWS (EKS, ECS, Lambda containers)
  • you want scans + tidy-up without extra tools

👎 Think twice when

  • publishing public/open-source images → Docker Hub or GHCR
  • deliberately multi-cloud → GHCR or self-hosted Harbor

Diagram ↗