๐ฑ Learn Docker & ECR the school way
Course 1 of 3 in the school trilogy โ before
Kubernetes runs your app and
ArgoCD deploys it, something has to
pack and ship it . That's this course: images, Dockerfiles, compose and multi-stage builds
on your laptop, then registries and AWS ECR in the cloud.
๐ฑ images ๐ layers
๐ Dockerfiles ๐ฝ๏ธ compose
๐จโ๐ณ multi-stage ๐ฆ AWS ECR
๐ณ Part 1 โ PACK IT (laptop only)
why containers end "works on my machine"
images = layer cakes ๐; the build cache
run, ports, env, logs, volumes, networks
compose the whole table; multi-stage; hygiene
โ๏ธ Part 2 โ SHIP IT (registries & ECR)
registries: the frozen-lunchbox warehouse ๐ฌ
rent your bank locker: a private ECR repo ๐ฆ
tag โ login (12h pass) โ push โ pull from EKS
janitor rules, scans, and CI doing it all for you
๐บ๏ธ The big picture โ one diagram, the whole journey
The whole course on one canvas: PACK IT (blue, lessons 1โ8) and SHIP IT
(orange, lessons 9โ12). Click it for the 4K version โ
great as a single reference.
๐ณ Part 1 โ PACK IT: Docker on your laptop (lessons 1โ8)
Only Docker Desktop needed โ zero cloud, zero cost. One git branch = one idea;
branch 07 contains lessons 01โ07.
โ๏ธ Part 2 โ SHIP IT: registries & AWS ECR (lessons 9โ12)
The bridge from laptop to cloud: where images live so that clusters can pull them.
Uses a real AWS account (pennies; cleanup shown).
# take the course locally (just Docker Desktop for Part 1):
git clone https://github.com/BaluRaut/learn-docker-school.git
cd learn-docker-school
git checkout lesson-01-why-containers # then open lessons/01-why-containers/README.md
๐ The lesson diagrams โ follow the numbers
Every lesson as one numbered box-and-arrow diagram, one after another โ
readable right here (blue = Docker, orange = ECR). Also on a
standalone page with jump navigation.
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
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
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
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
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
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
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)
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
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
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)
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
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
Start Lesson 01 โ
๐ All 12 lesson diagrams
๐งช Quiz
๐๏ธ Study plan
โฎ๏ธ Before & trade-offs
โธ๏ธ Next course: Kubernetes