CONT 201
cont-201 · v1.0.0
ivyx✓
Containers as the Unit of Deployment: put wave one's retriever in an image, watch the container disagree with the host, count what a rebuild redoes, address a second container by name, read exit codes, lose an index on purpose, find a deleted secret in a layer, and ship an image you can defend.
What this course is for
By the end of this course you can write a compose file that stands your service and its store up together, read the logs of a container that will not start, and name the difference between your machine and the image.
What you will be able to do
- Run one service on the host and in a container, and explain two different answers from one relative path
- Read an image layer by layer with history, inspect and find, and put a size on what the copy brought in
- Reorder two Dockerfile lines and predict from the file alone which steps a rebuild takes from the cache
- Stand two containers up with Compose, reach one from the other by service name, and say what localhost means inside a container
- Read a stopped container's exit code and log and sort it into finished, crashed or misconfigured before touching it
- Tell the writable layer from a volume by what survives a restart and what survives a recreate
- Find a file a running container cannot see in the layer that still carries it, and move configuration and secrets out of the image
- Justify every line of a shipped Dockerfile with a measurement, and prove two runs from nothing are the same run
Who it is for
Learners who finished RAG 101 and can write a Python function, and who now have to hand a working service to somebody else's machine.
Before you start
- PYTHON 101, for functions, files and the standard library the service is written in
- RAG 101, for the retriever, the corpus and the questions this course puts in a container
Lesson path
What is in an image, how it got there, and what a rebuild has to redo
- 1It works on my machine40 min
Run the retriever on the host, run it in a container, and get two different answers to one question
- 2What is actually in there55 min
Read the image layer by layer and find the three things the copy brought in that nobody meant to ship
- 3The rebuild that took two seconds55 min
Reorder two lines, measure the cached layer count, and say which edit invalidates what
Two containers on one network, and the ones that stop
- 4Two containers, one network55 min
Stand the service and its store up together and name what a service address is when it is not localhost
- 5The container that will not start55 min
Read an exit code and a log, and tell a crash apart from a container that did its job and stopped
What a container writes, where it goes, and what belongs outside the image
- 6What survives a restart55 min
Separate the writable layer from a volume, and lose an index on purpose
- 7Configuration is not code55 min
Move the corpus path and the port out of the image, and find the secret that was baked into a layer that is still there after it was deleted
The image you would ship, and the proof that it ships the same twice
- 8The image you would actually ship55 min
Base, user, healthcheck and size, each justified against a measurement rather than a habit
- 9From nothing to answering60 min
Stand the whole thing up in one command, verify it with the smoke questions, tear it down, and prove the second run is the same as the first
About this course
CONT 201 · Containers as the Unit of Deployment
Wave one ended with a retriever you built, measured and priced: BM25 over Northgate Motors' 52 documents, a lot table of 24 cars, a query log of a week. It runs in a notebook, on one machine, for one person. This course is about the first thing that changes when it has to run somewhere else: the thing you hand over stops being a folder of Python and becomes an image, and an image is a record of exactly what is inside it, which is not what your machine had. The tour proves it in five questions. The same 139 line service, run on the host and in a container built from its own folder, gives two different answers to two of them, because one relative path resolved against two working directories and the copy brought a stale snapshot of the corpus along.
The course does not explain containers; Docker's documentation does that
well and the reading list points at the pages. It puts wave one's
retriever in a container in front of you and measures what happens: how
many layers the image has and what each weighs, how many build steps a one
character edit redoes under two orderings of the same Dockerfile, what
localhost means from inside a container standing next to another, what
three exit codes and three logs say about three containers that stopped,
what survives a restart and what survives a recreate, where a deleted
secret still lives, and what each line of a shipped image is for.
Every number a graded cell checks comes from a recording made when the course was built, so the answers are the same on every machine and on a machine with no Docker at all. Every live cell runs your own Docker when you have one and prints what your machine says beside the recording. Layer counts, cached step counts, exit codes and addresses agree; sizes and seconds are your machine's, and the prose says so wherever it quotes one.
How this course teaches
Lesson 1 is a tour: it runs the service twice, asks five questions twice, and lets you predict how many answers match before it shows you. The eight lessons after it are graded work, each built the same way, and nine or ten of their cells are yours.
- A prediction you commit to before the cell runs. It is graded on the reasoning, not the guess, and being wrong here is the point.
- Warmups: a one line blank or a short exercise under the theory it practices, each with a four rung hint ladder behind it, where the last rung explains and still does not hand over the code.
- An exercise that is broken when you open it.
- A diagnose cell: code that runs, prints a confident and plausible conclusion, and is wrong. The evidence that refuses it is already on the screen.
- A challenge that ends in a sentence you write. The tutor grades the sentence, which means a green tick earned for the wrong reason can be taken back.
No cell in this course passes in the state it ships. That is deliberate, and it is checked mechanically before the course is published.
The particular danger of this subject is a command that answers a
different question from the one you asked. ls inside a container says a
deleted file is gone, and the file is in layer 7 of the image with its
token intact. docker ps says a container is Up, and the container is
answering nothing. docker run -d returns 0, and the process it started
crashed a second later. A build log says 5.3 seconds, and the number
that belongs to the Dockerfile is 1 of 4 steps cached. Every diagnose
cell is one of those, and every refusal is the record that answers the
right question: the layer listing, the health status, the exit code, the
cached count.
What you will be able to do
- Run one service on the host and in a container, and explain two different answers from one relative path.
- Read an image layer by layer with
history,inspectandfind, and put a size on what the copy brought in. - Reorder two Dockerfile lines and predict from the file alone which steps a rebuild takes from the cache.
- Stand two containers up with Compose, reach one from the other by
service name, and say what
localhostmeans inside a container. - Read a stopped container's exit code and log and sort it into finished, crashed or misconfigured before touching it.
- Tell the writable layer from a volume by what survives a restart and what survives a recreate.
- Find a file a running container cannot see in the layer that still carries it, and move configuration and secrets out of the image.
- Justify every line of a shipped Dockerfile with a measurement, and prove two runs from nothing are the same run.
The lessons
1. It works on my machine. The service on the host searches 52
documents; the same image, built with COPY . ., searches 27, because
data/docs.csv inside the folder is a snapshot from before the 2025
warranty edition and the listings. Two of five smoke answers differ: the
warranty question falls to the 2023 edition and the A-123 question to an
FAQ about mileage. Same code, same path, two working directories.
2. What is actually in there. Fifteen history rows, seven layers, four
of them the base's. The Dockerfile added three: a directory at 8.19 kB, a
copy at 94.2 kB and an install at 85.7 MB. The copy brought .env,
.venv and __pycache__, about 40 kB together in this fixture; the
install left 20 MB of pip cache behind, 500 times the three. The folder
you copied is 0.02 percent of the image.
3. The rebuild that took two seconds. A one character edit under the naive ordering keeps 1 of 4 steps and downloads the 19.4 MB wheel again; under the ordered file it keeps 3 of 5 and only the source copy runs. An edit to the dependency list keeps 1 of 5 either way. The recording's clock says 5.3 seconds against 0.3; the count is the number you keep, and you can predict it from the Dockerfile without a build.
4. Two containers, one network. One image, two roles. From inside the
service container localhost:8001 is refused and store:8001 answers,
because localhost is the caller's own loopback and store is a name
Compose resolves to 172.19.0.2. A lot request asked of the service comes
back answered_by: store with eight Kessel rows, and both containers log
it. depends_on orders starts and waits for nothing.
5. The container that will not start. Three containers, three Exited
rows, codes 1, 0 and 2: an uncaught FileNotFoundError on data/nope.csv,
an index job that finished, a program that printed its usage. docker run -d returned 0 for all three. The log names the cause in its last line. A
restart would have helped none of them and on-failure would have looped
two.
6. What survives a restart. The index job added three paths to its
writable layer and a fresh container from the same image had none of them.
A running container kept its index across docker restart and lost it to
rm plus run. A named volume carried the 21,309 byte index into a
container that never built it. A deploy is a recreate.
7. Configuration is not code. RUN rm .env made ls say the file was
gone and left it in layer 7 of nine, token and all, under a whiteout in
layer 8. Adding .dockerignore while keeping the rm failed the build at
step 6; removing the rm gave an image with the token in no layer. The
same image read 27 documents by default and 52 with DOCS_PATH set and
the corpus mounted.
8. The image you would actually ship. Uid 10001 where the naive image
ran as 0; a healthcheck that turned a container unhealthy after three
checks while docker ps said Up; about 20 MB saved, all of it
--no-cache-dir, with the .dockerignore changing the size by 151 bytes
and changing what shipped. One line is wider than the measurements
justify, and the challenge names it.
9. From nothing to answering. Zero containers, one up, both services
running with health starting, five smoke answers identical to the
host's from lesson 1, seven Torres rows through the store. One down,
two containers and one network removed, zero left. The second run matched
the first on every answer, every score and the base digest
78387bc3..., and the report says what that proves and what it does not.
Requirements
Python 3.10 or later with duckdb, which the service uses for the lot
table:
pip install duckdb
Docker is a tool, not a package, and requires.packages cannot install it.
Docker Desktop on macOS or Windows, or the docker engine with the compose
plugin on Linux, makes the live cells build and run containers on your
machine; the first build pulls python:3.12-slim and one wheel. Without
Docker every cell still runs, from the recording made when the course was
built, and every graded cell reads that recording either way. The live
cells publish the service on port 18000 and remove every container they
start; the images they build and one named volume, cont201_index, stay
until you remove them with the commands lesson 9 prints.
What to read outside this course
Docker's Dockerfile reference is the document to keep open; the page on
COPY and the build context is lesson 2's theory and the guide on layers
and the build cache is lesson 3's. The Compose networking page explains
why a service is reachable by name and why localhost inside a container
is that container. The best practices page on writing Dockerfiles is
lesson 8's checklist with reasons attached; the course's contribution is
that you measure each item before adopting it. For what a whiteout is,
the OCI image specification's layer section is short and exact.