feat(root04): author Containers & Docker

Adds all 8 ROOT 04 modules (why containers exist, images & containers, Docker CLI, container
networking, container storage, Dockerfile & image build, Docker Compose, containers →
Kubernetes) — 43 activities, using the nested Docker Engine Phase 6D built and tested. Modules
1, 2, and 8 are conceptual (no lab by design) — the honest bridge module (M8) explicitly names
what Kubernetes adds beyond what this course already taught, without re-teaching Kubernetes
itself.

Adds 5 new hands-on Docker scenarios plus 2 MCQs, all against the real nested Docker Engine:
docker-cli-basics (run/exec/inspect a real container), docker-container-networking (a genuine
"works internally, unreachable from host" port-publishing failure, diagnosed and fixed by
recreating the container with the correct `-p` flag), docker-container-storage (a real
destroy/recreate cycle proving named-volume persistence, not just described), docker-build-image
(a real Dockerfile, a real build, a real custom image run), and docker-compose-multiservice (a
real two-service Compose application with a real published port). All tested end-to-end via the
real scenario-validation API, including negative tests.

Wires rootnode-containers-assessment (2 required + 4 random-draw scenarios) using the existing
Phase 3B assessment engine.

This completes the entire ROOT_ Foundations sequence (ROOT 01-04) — see
docs/PHASE6E_ROOT_FOUNDATIONS_COMPLETION.md.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-26 17:08:14 -05:00
co-authored by Claude Sonnet 5
parent e68b6f445a
commit 682ef2de47
45 changed files with 1970 additions and 0 deletions
@@ -0,0 +1,67 @@
# Docker CLI
## The commands you'll use constantly
Module 2 introduced pull/run/stop/rm conceptually. This module adds the rest of the everyday
toolkit — and every one of them maps directly to a Linux concept you already have from ROOT 01.
## `docker ps` — what's running right now
```
$ docker ps
CONTAINER ID IMAGE STATUS NAMES
a1b2c3d4e5f6 nginx:alpine Up 2 minutes web
```
This is the container-level equivalent of ROOT 02's `ps aux` — "what's actually running." Add
`-a` to see stopped containers too, not just running ones.
## `docker logs` — what has it been saying?
```
$ docker logs web
```
The container-level equivalent of reading a service's log file from ROOT 02 — except Docker
captures a container's stdout/stderr automatically, so there's no config needed to find WHERE
the logs live, unlike a traditional service.
## `docker exec` — run a NEW command inside an ALREADY-running container
```
$ docker exec web sh -c 'cat /etc/nginx/nginx.conf'
```
Different from `docker run`, which creates a brand-new container — `exec` reaches INTO an
existing, running one, exactly like ROOT 01's `ps`/inspection commands but scoped to one
specific container's process namespace.
## `docker inspect` — the full, detailed truth about a container
```
$ docker inspect web --format '{{.State.Running}}'
true
```
Returns a large JSON document with everything Docker knows about a container — `--format` lets
you extract just the one field you care about, rather than reading the whole thing.
## `docker stop` vs `docker rm`
`docker stop` gracefully stops a running container (sends SIGTERM, then SIGKILL after a grace
period — literally ROOT 01's process-signals lesson, applied to a container's main process).
`docker rm` deletes a STOPPED container entirely — `docker rm -f` combines both (force-stop then
remove) in one step.
## Instructor Notes
**Lesson goal:** Explicitly map every Docker CLI command back to the equivalent ROOT 01/02
Linux concept students already have — this is a translation exercise, not new material.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** confusing `docker run` (creates a new container) with
`docker exec` (runs a command in an existing one) — a very common early mixup.
**Demo idea:** run `docker exec` against a container, then immediately `docker run` the same
image again, and compare `docker ps` before/after to show the difference concretely.
@@ -0,0 +1,62 @@
# Demonstration: `run` Creates, `exec` Reaches In
## OBSERVE
```
$ docker run -d --name web nginx:alpine
$ docker ps --format '{{.Names}}'
web
```
One container exists.
## HYPOTHESIS
Predict: will `docker exec web echo hello` create a SECOND container?
## INSPECT
```
$ docker exec web echo hello
hello
$ docker ps --format '{{.Names}}'
web
```
Still exactly one container — `exec` ran a new command INSIDE the existing one, it never
created anything new.
## CHANGE
Now actually run the same image again:
```
$ docker run -d --name web2 nginx:alpine
$ docker ps --format '{{.Names}}'
web2
web
```
Now two containers exist — because `run`, unlike `exec`, always creates a NEW container.
## VERIFY
```
$ docker logs web | tail -3
$ docker inspect web --format '{{.State.Running}}'
true
```
Both containers are independent, each with their own logs and state — exactly as Module 2's
"one image, many containers" demonstration showed.
## Instructor Notes
**Demo goal:** Directly contrast `run` and `exec`'s effect on the container COUNT — this is the
most common early confusion and deserves a side-by-side comparison.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** trying to `exec` into a container that isn't running yet
(`exec` requires an ALREADY-running target) — a good moment to connect back to `docker ps`
first.
@@ -0,0 +1,39 @@
# Knowledge Check: Docker CLI
---
**1. What's the real difference between `docker run` and `docker exec`?**
*Answer:* `docker run` always creates a brand-new container from an image. `docker exec` runs a
new command inside an ALREADY-running container — no new container is created.
---
**2. Which command is the container-level equivalent of ROOT 02's "what's running" question
(`ps aux` / service inspection)?**
*Answer:* `docker ps` (add `-a` to include stopped containers too).
---
**3. Why doesn't `docker logs` require you to know a specific log file path, unlike a
traditional Linux service?**
*Answer:* Docker automatically captures a container's stdout/stderr output — there's no
separate log file configuration needed the way ROOT 02's services required.
---
**4. What does `docker stop` actually send to a container's main process, and why does that
matter?**
*Answer:* SIGTERM first (a polite shutdown request, giving the process a chance to clean up),
then SIGKILL after a grace period if it hasn't exited — the exact same signal discipline ROOT 01
taught for regular Linux processes, applied here to a container's main process.
## Instructor Notes
**Facilitation:** Question 1 is the single most important check in this module — revisit the
demo if students get it wrong.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,29 @@
# Guided Exercise: Which Docker Command Actually Does This?
This is a paper exercise — commit to an answer before checking it in the Lab.
## Your task
For each goal, name the ONE Docker command you'd use:
1. "See every container, including ones that have stopped."
2. "Run a one-off diagnostic command inside a container that's already running."
3. "Read what a container has printed to its logs so far."
4. "Check the exact value of one specific field (like whether it's currently running) without
reading the entire inspect output."
5. "Completely remove a running container in one step, without stopping it first separately."
## A worked shape to check yourself against
1. `docker ps -a`
2. `docker exec <container> <command>`
3. `docker logs <container>`
4. `docker inspect <container> --format '{{...}}'`
5. `docker rm -f <container>`
## Instructor Notes
**Facilitation:** Have students justify why each answer fits the described GOAL specifically,
not just recite familiar syntax.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,24 @@
# Reflection: The Whole Toolkit Was Already Familiar
## Reflection questions
1. Which Docker command in this module felt like "a new version of something I already knew"
from ROOT 01 or ROOT 02? Which felt genuinely new?
2. You ran, inspected, execed into, and removed a real container this module. What's the ONE
command you'd reach for first if a container "seemed broken" and you didn't know why yet?
## Real Ops takeaway
**Every Docker command in this module is a direct translation of a Linux skill you already
had.** `docker ps` is `ps aux`. `docker logs` is reading a log file, minus the config. `docker
exec` is reaching into a running process. This is exactly why ROOT 01-02 came before ROOT 04 —
containers don't replace Linux fundamentals, they wrap them in a specific, consistent interface.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 2's honest answer is usually `docker ps`
or `docker logs` — a good moment to connect back to ROOT 02's five-question service checklist.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.