Package any app into a container that runs the same everywhere.
Module 6 · The "aha!" moment of DevOps. Free · No cloud account needed.
Beginner Containers ~45 minBy the end of this module you will be able to:
Dockerfile for a real web appPrerequisites: A terminal and basic command-line comfort (Modules 2–3). No prior Docker knowledge.
You finish an app on your laptop. It works perfectly. You send it to a teammate — and it breaks. Different Python version, a missing library, the wrong operating system. This is the famous:
The root cause: your app depends on its environment (OS, runtime, libraries, config) — and that environment is different on every machine.
A container solves this by packaging your app together with everything it needs to run into one sealed box. That box runs identically on your laptop, your teammate's, a test server, and production.
Before shipping containers, cargo was loaded loose — slow, and every ship handled it differently. The steel container standardized everything: any crane, any ship, any truck handles the same box. Docker does this for software: your app, standardized into a box that any machine with Docker can run.
A VM virtualizes a whole computer (its own OS) — gigabytes in size, slow to boot. A container shares the host's OS kernel and only packages your app + its dependencies — megabytes in size, starts in milliseconds. That lightness is why containers won.
Almost all of Docker comes down to three ideas. Get these and everything else clicks.
| Term | What it is | Analogy |
|---|---|---|
| Image | A read-only template: your app + dependencies, frozen. Built once, never changes. | A class, or a cookie cutter |
| Container | A running instance of an image. You can start many from one image. | An object, or the cookie |
| Registry | An online store for images (e.g. Docker Hub). You push to share and pull to download. | GitHub, but for images |
Dockerfile → docker build → Image → docker run → Container → docker push → Registry
A Dockerfile is the recipe — a plain text file of instructions for building an image. You'll write one in the lab.
Install Docker Desktop (free for personal use, learning, and small businesses). It bundles everything you need on Mac, Windows, and Linux.
Get it from docker.com/products/docker-desktop. On Windows, accept the WSL 2 prompt if asked. Then launch the app once so the engine starts.
Verify it's working — open your terminal and run:
If you see "Hello from Docker!", Docker pulled a tiny image from the registry, ran it as a container, and it printed a message — you just ran your first container. 🎉
Cannot connect to the Docker daemon means the engine isn't running. Open the Docker Desktop app and wait for the whale icon to say "Engine running," then retry.
We'll containerize a tiny Python Flask web app — the same sample app we reuse through the whole course. Follow along; every command is copy-paste.
You can download the complete starter project (every file used across the course). But typing it out the first time is the best way to learn — we recommend following along.
app.pyA minimal web server that returns a page. Create a file called app.py:
host="0.0.0.0"?Inside a container, 127.0.0.1 means "only this container." Binding to 0.0.0.0 lets traffic from your host machine reach the app. Forgetting this is the #1 reason a containerized web app "won't load."
requirements.txtDockerfileCreate a file named exactly Dockerfile (no extension). We explain every line in the next section.
.dockerignoreKeeps junk out of your image and speeds up builds:
The -t flag tags (names) your image. The . means "build using this folder."
Confirm it exists:
-p 8080:5000 maps port 8080 on your machine to port 5000 inside the container. -d runs it in the background; --name gives it a friendly name.
Now open http://localhost:8080 in your browser. You should see the whale greeting — served from inside your container. ✅
Your app is now running with zero Python or Flask installed directly on your machine — everything lives in the container. Delete the container and your system is spotless.
Create a free account at hub.docker.com, then:
Anyone, anywhere, can now run your exact app with one command: docker run -p 8080:5000 YOUR_USERNAME/notes-app:1.0. That is the power of Docker.
Each instruction adds a layer to your image. Understanding them is the core skill of this module.
| Instruction | What it does |
|---|---|
FROM python:3.12-slim | Start from an official, slim Python base image. You never build from scratch. |
WORKDIR /app | Set the working directory inside the container. Later commands run here. |
COPY requirements.txt . | Copy just the deps file first — so the next (slow) step is cached. |
RUN pip install ... | Install dependencies during the build, baking them into the image. |
COPY . . | Copy the rest of your code into the image. |
EXPOSE 5000 | Document which port the app listens on (informational). |
CMD ["python","app.py"] | The command that runs when the container starts. |
requirements.txt before the code?Docker caches each layer. If you change only your code (not your dependencies), Docker reuses the cached pip install layer — rebuilds drop from minutes to seconds. This ordering trick is the most important Dockerfile optimization for beginners to learn.
The 90% of Docker commands you'll actually use day to day. Bookmark this.
| Command | What it does |
|---|---|
docker build -t name . | Build an image from the Dockerfile in this folder |
docker images | List images on your machine |
docker run -d -p 8080:5000 name | Run a container in the background, map ports |
docker ps | List running containers |
docker ps -a | List all containers (incl. stopped) |
docker logs <name> | Show a container's output |
docker exec -it <name> bash | Open a shell inside a running container |
docker stop <name> | Stop a running container |
docker rm <name> | Delete a (stopped) container |
docker rmi <image> | Delete an image |
docker pull <image> | Download an image from a registry |
docker push <image> | Upload your image to a registry |
docker system prune | Clean up unused containers, images, networks |
| Symptom | Likely cause & fix |
|---|---|
| Cannot connect to the Docker daemon | Docker Desktop isn't running — open the app and wait for "Engine running." |
| Page won't load in browser | App bound to 127.0.0.1 instead of 0.0.0.0, or wrong -p mapping. |
port is already allocated | Another process uses 8080 — change the host port, e.g. -p 8081:5000. |
| Container exits immediately | App crashed on start — run docker logs <name> to see the error. |
| Code change not showing | You must docker build again — images are snapshots, not live. |
| "name is already in use" | A container with that name exists — docker rm <name> first. |
Cement it by doing. Try these before moving on:
/about that returns your name, rebuild, and run it.docker exec -it notes bash to look around inside the container, then exit.Explain containers, write a Dockerfile, build an image, run it, and share it. That's the foundation everything else in DevOps builds on.
Next up: Module 7 — Docker Compose, where you'll run your app and a database together with a single command.