ABCsteps lesson path
Docker: Make Local Software Repeatable
Understand containers by packaging an app into a repeatable environment that behaves consistently across machines. Build one artifact, keep one review trail, and make the work easy to inspect later.
- Lesson
- 06
- Time
- 45 min
- Access
- public lesson
Learning objective
Understand what containers solve and how Docker packages an application.
Lab outcome
Write a Dockerfile and run the app in a container.
Module milestone
Containerize and share a working app through a verified deployment path.
Lesson proof workflow
Read, build, then review the evidence.
- Step 1ReadStart with Container basics before touching tools.
- Step 2BuildBuild toward: Write a Dockerfile and run the app in a container.
- Step 3ReviewReview the evidence using Runtime reproducibility.
Toolchain
Containers make software repeatable across machines.
These are the practical surfaces used in this lesson. Learn the habit first, then connect it to the wider engineering ecosystem.
Package the app and its environment together.
Run the application inside a predictable container.
Read package and configuration files that shape the build.
Proof of work
Leave one inspectable trail from this lesson.
The useful output is not a passive note. It is a small artifact another person can inspect: a working file, a command result, a commit, a screenshot, a README note, or a demo link.
Lesson lab: Write a Dockerfile and run the app in a container.
Tool and platform logos are ecosystem references only: no affiliation, endorsement, interview access, hiring promise, salary promise, or placement guarantee.
Build
Produce the artifact
Complete the lab and keep the result visible: Write a Dockerfile and run the app in a container.
Record
Save review evidence
Capture what changed, what broke, and how Container basics became clearer through the work.
Explain
Write the vocabulary
Use your own words for Dockerfile reading and Runtime reproducibility; this is what makes the lesson inspectable later.
Skills companies recognize
Translate the lesson into inspectable work language.
This lesson turns one small lab into the language a learner can use in a README, demo note, or technical conversation. The point is not to collect logos; the point is to explain work clearly enough that another engineer can inspect it.
Where this skill appears
Cloud and backend teams care about repeatability because software must run beyond the learner laptop.
Ecosystem references
Platform and company logos are ecosystem references only: no affiliation, endorsement, interview access, hiring preference, salary outcome, or placement guarantee.
README line
Name the artifact
Lab proof: Write a Dockerfile and run the app in a container. Connect it to Container basics so the result reads like work, not a passive note.
Review line
Explain the stack
Use Docker, Node.js, JSON to explain Dockerfile reading and what changed between the first attempt and the inspected result.
Conversation line
Answer with evidence
If a team asks about Runtime reproducibility, use this proof line: Show the Dockerfile, the run command, and proof that the same app starts inside the container.
Proof translation
Skill signal
Container basics is the market word. The lesson makes it visible through a small working artifact.
Proof artifact
The inspectable artifact is: Write a Dockerfile and run the app in a container.
Interview answer
Use Dockerfile reading and Runtime reproducibility to explain what changed, what failed, and how you verified it.
Paid guidance
Read publicly. Upgrade when guidance will help you finish.
This lesson remains part of the public written syllabus. Paid help is online-only and human-led: video walkthroughs as they roll out, live class context, WhatsApp Q&A, and project review around the same work.
No account wall, automated checkout, or placement promise is introduced here. Enrollment stays human-led by WhatsApp or call, and the useful proof remains the learner's own artifact.
Public
Written lesson stays open
Read the prepare and review material for lesson 06 on the public site before buying anything.
Recorded
Recorded and live guidance clarify the work
Paid guidance can add founder-led video walkthroughs as they roll out and live online class context; the teaching explains the work, but does not replace the written lesson.
Human
Questions use real context
When stuck, useful guidance starts from the route, error, screenshot, repo fragment, and the lab artifact: Write a Dockerfile and run the app in a container.
Phase 1 · Briefing
Lesson briefing
Before You Study (5 mins)
Lesson focus: Why does Netflix work on your TV, your phone, and your laptop exactly the same way? The answer is Docker. It stops the dreaded error: "But it works on MY machine!"
What you should have ready:
- Docker Desktop installed and running (download from docker.com)
- Your saved Snake Game from Lesson 01
- Antigravity open — we'll use AI assistance for the Dockerfile
- Terminal open in your project folder
- About 45 minutes of focused time
The Concept
A container is a way to package your application and the exact environment it needs to run, into a single shippable unit. You hand someone a container; they run it; it works the same on their machine as it did on yours. No "but I have a different version of Node" excuses.
People often confuse containers with virtual machines (VMs). They are not the same:
| Aspect | Container | Virtual Machine |
|---|---|---|
| What it shares | The host operating system's kernel | Nothing — runs its own kernel |
| Boot time | Milliseconds | Seconds to minutes |
| Size on disk | Megabytes | Gigabytes |
| Isolation | Process-level (Linux features) | Hardware-level (a hypervisor) |
| Density on one host | Hundreds | Tens |
The reason a container can boot in milliseconds is that it's not booting an OS. It's just starting a process inside an isolated view of the existing kernel. Three Linux features make this possible:
- Namespaces — control what a process can see (its own PID 1, its own network interfaces, its own filesystem tree)
- cgroups — control what a process can use (CPU time, memory, disk I/O limits)
- Union filesystems — let images be built up in layers, with each layer reused across many containers
Docker is a friendly UX wrapper around these three kernel features. When you run docker run nginx, Docker asks the Linux kernel to create a new set of namespaces and cgroups, mounts a layered filesystem, and starts the nginx process inside that isolated environment.
Want the deep dive? This lesson keeps the concept short. The companion article How Docker Actually Works — Container Internals Explained walks through namespaces, cgroups, and OverlayFS with real
/procand/sys/fs/cgrouppaths you can verify yourself.
The other word you'll hear constantly is image. An image is a template — a packaged filesystem snapshot, in layers, that contains your app and its dependencies. A container is a running instance of an image. One image, many containers. Like one class definition and many instances.
Layers and the build cache
The reason docker build runs fast on subsequent builds is the layer cache. Each instruction in a Dockerfile produces one layer:
FROM node:20-alpine # layer 1: base image (~50MB)
WORKDIR /app # layer 2: filesystem change
COPY package*.json ./ # layer 3: dependency manifests
RUN npm ci --production # layer 4: installed node_modules
COPY . . # layer 5: your source code
EXPOSE 3000 # layer 6: metadata only
CMD ["node", "server.js"] # layer 7: default command
Docker caches each layer by content. The next time you build, if package.json hasn't changed, layers 1-4 reuse the cache and only layer 5 (your code) rebuilds. A clean rebuild that would take 90 seconds drops to 5. The Dockerfile instruction order matters — putting COPY . . before npm ci would invalidate the cache on every code change. Always copy dependency manifests, install, and only then copy source.
This is the single biggest practical lesson hiding inside "Docker": the build cache is your friend if you order instructions from least-frequently-changing to most-frequently-changing.
Why containers won
Before Docker (2013), shipping software meant either:
- "Here is a tar.gz. Good luck installing 47 dependencies in the right order."
- "Here is a 4GB virtual machine image. Allocate 8GB of RAM and pray your laptop survives."
Containers replaced both. A 50MB image starts in milliseconds, runs anywhere with a Linux kernel (Mac, Windows via WSL, every cloud), and packages exactly what your app needs. Netflix, Spotify, Stripe, every company that ships software at scale today runs on containers. The pattern is universal because the problem it solves — "will my code run somewhere other than my laptop" — is universal.
Quick Concepts
| Term | Simple Meaning |
|---|---|
| Container | A "Magic Lunchbox" that keeps your app fresh anywhere |
| Image | The recipe for the lunchbox (what goes inside, in what order) |
| Dockerfile | The instruction sheet that builds the recipe |
| Port | A specific door on your computer (3000, 8080) where traffic enters |
| Layer | One step of the recipe — reused across many containers |
What We Will Build
By the end of this lesson, you will have done these specific things:
- Verified Docker Desktop is running by typing
docker --versionin the terminal. - Opened your Snake Game project folder.
- Asked Antigravity to write a
Dockerfilefor a simple Node.js or static-HTML project, and inspected it line by line. - Built the image with
docker build -t snake-game .(note the trailing dot). - Run the container with
docker run -p 3000:3000 snake-game. - Loaded
http://localhost:3000in your browser and confirmed your game runs inside the container. - Stopped the container and inspected the image with
docker imagesanddocker history.
When you finish, you will have shipped your first container. Not metaphorically — actually.
Common Pitfalls
These are the four mistakes most people make in their first Docker build, in roughly the order they hit:
- "Port already in use" — you ran the container, then ran it again without stopping the first. Both want port 3000. Fix:
docker psto see what's running,docker stop <id>to stop it. Or use a different host port:docker run -p 3001:3000 snake-game. - "My changes aren't showing up" — you edited a source file but the container is still serving the old code. The image was built from the old code; the container runs that frozen image. Fix: rebuild (
docker build -t snake-game .) or use a volume mount in development (-v $(pwd):/app). The first is correct for shipping; the second is correct for iterating. - Image is 1.5GB — you used
node:20(full Debian) instead ofnode:20-alpine(small Linux variant). Or youCOPY .before.dockerignorewas set up, sonode_modulesand.gitgot baked in. Fix: prefer slim/alpine base images, write a.dockerignorethat excludesnode_modules,.git,.env, and other local-only files. - "docker: command not found" — Docker Desktop isn't running on your Mac/Windows machine. The
dockerCLI talks to the Docker daemon; if the daemon isn't running, the CLI returns this error. Fix: open Docker Desktop and wait for the whale icon to settle.
If you hit a pitfall not on this list, the fix is almost always in docker logs <container-id> — the container's stdout/stderr is the first place to look.
Think About
Before studying, consider:
- Have you ever sent a file to a friend and they couldn't open it because they "didn't have the right font"? Now imagine your whole app is the file, and the font is Node version 20.11 with these 47 npm packages and this exact Linux distribution. That's the problem Docker solves.
- If a container only takes milliseconds to start, what could you do with that speed that you couldn't do with virtual machines? (Hint: think about how Netflix handles a sudden traffic spike.)
- Why does the order of instructions in a
Dockerfilematter? What would go wrong if you putCOPY . .beforeRUN npm ci?
By the End
After this lesson, you'll:
- ✅ Understand what containers actually are at the kernel level
- ✅ Have written your first
Dockerfile(with AI assistance, but you'll read every line) - ✅ Have built your first image and run your first container
- ✅ Be able to explain the difference between an image and a container
- ✅ Know where to read more when you want to go deeper (the companion blog post)
Let's package your app. 📦
Next lesson · 07
Cloudflare Tunnel: Share a Local App Safely
Learn what a tunnel is, when it is useful, and how Cloudflare can expose a local app for demos without pretending it is full production hosting.