← Back to the course home

📐 The 12 lessons as diagrams

Part 1: Docker on your laptop (blue, lessons 1–8) · Part 2: registries & ECR (orange, lessons 9–12). Follow the circled numbers 1 → 2 → 3 in each picture.

1 🍱 Why containers — the end of "works on my machine"

Pack the app WITH everything it needs; every machine opens the identical box.

🧑‍💻 your laptop: works! node 20 installed, all libs there 💥 teammate's laptop: crash node 14, missing libs, wrong path 1 the naked-app problem 🍱 the container app + node 20 + libs + config everything INSIDE the box (shares the host's kernel — way lighter than a VM) 2 💻 laptop A ✅ 💻 laptop B ✅ ☁️ AWS server ✅ 3 identical, everywhere

Read full lesson 01 →

2 🎂 Images & layers — the cake and the cache

Every Dockerfile line bakes one layer; unchanged layers are reused from cache.

🎂 image = a layer cake FROM node:20-alpine (pre-baked) WORKDIR /app COPY server.js . CMD ["node","server.js"] 1 🔁 build again, nothing changed every layer from cache → finishes in ~1 second 2 ✏️ edit server.js bottom layers: cached ✅ COPY + above: rebuilt 🔨 3 💡 the trick order lines from rarely-changing (bottom) to often-changing (top) = fast builds forever

Read full lesson 02 →

3 📝 The Dockerfile — reading the recipe card line by line

Seven instructions cover 95% of real Dockerfiles — this repo's app uses them all.

📝 app/Dockerfile FROM node:20-alpine WORKDIR /app COPY server.js . ENV PORT=3000 EXPOSE 3000 USER node CMD ["node","server.js"] 1️⃣ start from a pre-baked box: tiny Linux + Node — you never install Node yourself again 2️⃣ COPY puts YOUR code inside the box (.dockerignore decides what may enter) 3️⃣ ENV = default settings · EXPOSE = documentation ("this app listens on 3000") 4️⃣ USER: don't run as root (lesson 08) · CMD: what happens when the box is opened — exactly ONE process per container, in the foreground

Read full lesson 03 →

4 🍽️ Running containers — lunch time

docker run opens the box; ports are the serving window; logs and exec are your eyes and hands.

🧊 image hello-school:v1 🏃 container node server.js (PID 1) own filesystem, own network -e APP_VERSION=v2 → settings in 1 docker run 🪟 -p 3000:3000 laptop:3000 → box:3000 2 📜 docker logs 🔧 docker exec 3 🛑 docker stop → SIGTERM, clean exit 4

Read full lesson 04 →

5 🧊📞 Volumes & networks — the shared fridge and the intercom

Containers are disposable; volumes make data survive. Networks let containers call each other by NAME.

📞 docker network — the intercom 📦 container "web" the app 📦 container "proxy" calls http://web:3000 1 a NAME, not an IP — Docker DNS resolves it (k8s Services say hi 👋) 🧊 volume — the fridge lives OUTSIDE containers, survives docker rm 💪 2 📂 bind mount a laptop folder mapped in — live-edit code & config 3

Read full lesson 05 →

6 🍽️🍽️ Docker Compose — set the whole table with one command

One YAML file describes every service; docker compose up builds and starts them all, wired together.

📄 compose.yml web: build ./app proxy: nginx + config ports: 8080:80 1 🍽️ the table — one shared network 📦 web the app · NOT exposed reachable only by name 📦 proxy nginx → http://web:3000 🪟 the ONLY door: :8080 3 2 compose up --build one command up · one command down (docker compose down) · same file works on every teammate's laptop 4

Read full lesson 06 →

7 👨‍🍳 Multi-stage builds — cook in the kitchen, pack only the food

Build tools live in a throwaway stage; only the result ships. Images shrink dramatically.

👨‍🍳 stage 1: the KITCHEN FROM node:20-alpine AS builder node + tools + source (~180MB) RUN node generate.js → index.html 🗑️ thrown away after the build 1 🍱 stage 2: the LUNCHBOX FROM nginx:alpine (~50MB) COPY --from=builder index.html no node, no tools, no source — just the result. THIS ships. 🚀 3 2 only the food crosses smaller image = faster pushes/pulls (lesson 11), fewer things to attack (lesson 08)

Read full lesson 07 →

8 🏷️ Image hygiene — label your boxes, don't pack your keys

The four habits that separate hobby images from production images.

🏷️ 1 · real tags, never :latest in prod hello-school:v1 / :git-sha — ":latest" is a floating label; you can't roll back to "latest" 1 🙈 2 · .dockerignore everything private .git, .env, node_modules, logs — COPY can't leak what it cannot see 2 👤 3 · USER node — never run as root a break-in to a root container is a break-in to the machine; drop privileges in the image 3 🪶 4 · small base images (alpine/slim) node:20 ≈ 1.1GB vs node:20-alpine ≈ 180MB — less to pull, less to patch, less to attack 4

Read full lesson 08 →

9 🏬 Registries — the frozen-lunchbox warehouse

A registry stores images so OTHER machines can pull them — the bridge from laptop to cloud.

🧑‍💻 your laptop image built locally 🏬 registry — the warehouse 📚 repository: hello-school shelf for ONE app's versions 🏷️ tags: v1, v2, abc123… 🔢 digest = tamper-proof fingerprint 1 docker push ☸️ EKS cluster pulls at deploy 💻 teammate docker pull 2 Docker Hub = the public warehouse · ECR = your company's private one (next lesson) 3

Read full lesson 09 →

10 🏦 ECR setup — renting the bank locker

Create a private repository once; get a fresh 12-hour pass whenever you visit.

🏗️ rent the locker (once) terraform apply (ecr/ecr.tf) or: aws ecr create-repository 1 ☁️ AWS — ECR 🔐 repository: hello-school (private) address: ACCOUNT.dkr.ecr.REGION.amazonaws.com/hello-school 🎫 the 12-hour day pass aws ecr get-login-password | docker login … 2 3 now docker push/pull may enter 🔑 who may enter at all = IAM (your AWS user/role needs ecr:* permissions — the bank checks ID first)

Read full lesson 10 →

11 🧹 Push, pull & lifecycle — filing boxes and the janitor

The tag IS the address; push files the box, EKS pulls it, the janitor keeps the locker tidy.

🏷️ address the box docker tag hello-school:v1 \ ACCOUNT.dkr…/hello-school:v1 1 🏦 ECR locker 📦 v3 (newest) 📦 v2 📦 v-old… expired 🧹 2 docker push ☸️ EKS deployment image: ACCOUNT.dkr…/ hello-school:v3 → pulled 3 🧹 lifecycle policy "keep newest 10, expire rest" (ecr/lifecycle-policy.json) 4

Read full lesson 11 →

12 📮 CI to cloud — the courier files the copies

In real life a robot does lessons 1–11 on every push — and hands the baton to the next two courses.

🧑‍💻 dev git push 📮 CI — the courier robot ✅ test → 🍱 build → 🏷️ tag = commit SHA → 🔑 12h pass → push (the k8s course's CircleCI does exactly this) 1 🏦 ECR 🛡️ scan on push — every image checked for known vulnerabilities 2 ☸️ next course: Kubernetes RUNS these images across a cluster 🤖 then: ArgoCD DEPLOYS them from git, automatically, forever 3 4

Read full lesson 12 →