Docker Containerization Explained Simply (with Diagrams and Real Code)

Docker Containerization: The Essentials in One Article — Real Code, Diagrams and Concrete Steps, Excerpts from a 41-Lesson Course.

Docker Containerization Explained Simply (with Diagrams and Real Code)

A straight-to-the-point guide: Docker Containerization broken down with diagrams, concrete examples and tested commands. All from a structured 12-chapter course — here are the best parts.

tl;dr
  • Install an UBUNTU VM
  • Discover docker
  • Essential commands
  • Dockerfile
  • Containerize Flask
~$ cat ./parcours.md # Docker Containerization — 11 chapters
01
Install an Ubuntu VM
→ Download VirtualBox and the Ubuntu ISO→ Create the VM and install Ubuntu+ 1 more lessons
02
Discover docker
→ What is Docker and why use it?→ Install Docker on Ubuntu+ 1 more lessons
03
Essential commands
→ The fundamental commands→ Ports, volumes and environment variables+ 2 more lessons
04
Dockerfile
→ Anatomy of a Dockerfile→ Build and run your first image+ 1 more lessons
05
Containerize Flask
→ Flask reminder and application creation→ Flask Dockerfile, build and run+ 1 more lessons
06
Containerize FastAPI
→ FastAPI reminder and API creation→ FastAPI Dockerfile and Swagger UI+ 1 more lessons
07
Containerize Streamlit
→ Streamlit reminder and dashboard creation→ Streamlit Dockerfile and headless configuration+ 1 more lessons
08
Docker-compose
→ Why Docker Compose?→ Flask + PostgreSQL project+ 2 more lessons
🏁
Final project (+ 3 chapters along the way)
→ You leave with a concrete and demonstrable project

Anatomy of a Dockerfile

NOTEObjective — Understand what a Dockerfile is, master each instruction and write your first Dockerfile to create a custom Docker image.
WARNINGBefore you begin — This lab assumes you have completed the previous modules. If you encounter name conflicts, ports already in use, or if Docker no longer responds correctly, use these commands to start from scratch:
bash
# Stop ALL running containers
docker stop $(docker ps -a -q)

# Remove ALL containers
docker rm $(docker ps -a -q)

# Remove ALL images (optional)
docker rmi $(docker images -q)

# Force removal if an image resists
docker rmi -f $(docker images -q)
⚠ Warning — These commands delete everything. Use them only if you want to start from a clean environment. The -f (force) option also removes images used by containers.

Learning objectives

TIPAt the end of this module — You will be able to master these essential skills.

What is a Dockerfile?

A Dockerfile is a text file that contains a series of instructions to build a Docker image. It is like a recipe: each instruction is a step that transforms the base image into your custom image.

NOTEAnalogy — Think of the Dockerfile as a cooking recipe:
  • FROM = Basic ingredients (flour, butter...)
  • WORKDIR = Workspace (kitchen table)
  • COPY = Add ingredients (sugar, eggs...)
  • RUN = Prepare (mix, cook...)
  • EXPOSE = Indicate presentation (serving dish)
  • CMD = Serve the dish (final command)

Base image

The Dockerfile always starts from an existing image (FROM). We never start from scratch.

Instructions

Each line is an instruction that modifies the image: copy files, install packages, configure...

Final image

The result is a custom image ready to be launched with docker run.

Main instructions

FROM – Base image

First instruction of a Dockerfile. It defines the starting image on which we build.

output
FROM python:3.11-slim
NOTEExplanation — We use the official Python 3.11 image in its slim version (lightweight version, without unnecessary tools). This gives us a Linux system with Python 3.11 already installed.

WORKDIR – Working directory

Defines the working directory inside the container. All subsequent instructions (COPY, RUN, CMD) will execute in this folder.

output
WORKDIR /app
TIPBest practice — Always use WORKDIR instead of RUN cd /app. WORKDIR creates the folder automatically if it does not exist and persists for all subsequent instructions.

COPY – Copy files

Copies files from your machine (the "build context") into the container.

output
COPY . .

The first . = the current folder on your machine. The second . = the WORKDIR inside the container (/app).

Layers, cache and best practices

NOTEObjective — Understand Docker's layer and cache system, and apply best practices to write optimized Dockerfiles.
WARNINGBefore you begin — This lab assumes you have completed the previous modules. If you encounter name conflicts, ports already in use, or if Docker no longer responds correctly, use these commands to start from scratch:
bash
# Stop ALL running containers
docker stop $(docker ps -a -q)

# Remove ALL containers
docker rm $(docker ps -a -q)

# Remove ALL images (optional)
docker rmi $(docker images -q)

# Force removal if an image resists
docker rmi -f $(docker images -q)
⚠ Warning — These commands delete everything. Use them only if you want to start from a clean environment. The -f (force) option also removes images used by containers.

Learning objectives

TIPAt the end of this module — You will be able to master these essential skills.

Each instruction = 1 layer

When Docker executes a Dockerfile, each instruction (FROM, RUN, COPY, etc.) creates a new layer. A Docker image is a stack of layers piled on top of each other.

output
FROM python:3.11-slim     ← Layer 1 (base image)
WORKDIR /app              ← Layer 2
COPY requirements.txt .   ← Layer 3
RUN pip install ...       ← Layer 4
COPY . .                  ← Layer 5
CMD ["python", "app.py"]  ← Layer 6 (metadata)
NOTEWhy layers? — Layers allow Docker to:
  • Share common layers between multiple images (e.g.: all Python images share the same base layer)
  • Cache layers to speed up builds
  • Reduce disk space by storing each layer only once

The Docker cache

Docker caches each layer. During a rebuild, Docker checks if a layer has changed. If nothing has changed, it reuses the cached layer instead of rebuilding it.

WARNINGFundamental rule — If a layer changes, all subsequent layers are rebuilt, even if they have not changed. This is why the order of instructions is crucial.

Bad order vs good order

BAD: requirements after COPY . .

output
FROM python:3.11-slim
WORKDIR /app
COPY . .                            ← All source code
RUN pip install -r requirements.txt ← Install dependencies
CMD ["python", "app.py"]
WARNINGProblem — Every time you modify your code (even a space in app.py), the COPY . . layer changes. Because it is before RUN pip install, Docker must reinstall all dependencies on every build. On a project with many dependencies, this can take several minutes.

GOOD: requirements before COPY . .

output
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .             ← Only the dependencies
RUN pip install -r requirements.txt ← Installation (cached if requirements.txt has not changed)
COPY . .                            ← Source code (changes often)
CMD ["python", "app.py"]
TIPAdvantage — When you modify your source code, only the COPY . . layer changes. Dependencies (pip install) are cached and are not reinstalled. The build time drops from several minutes to a few seconds.

Bad order

Good order

Demonstration: observe the cache

TIPGuided exercise — Let's observe the cache in action with two successive builds.

Step 1: Create the project

bash
mkdir ~/demo-cache
cd ~/demo-cache

Create requirements.txt:

bash
touch requirements.txt
nano requirements.txt

Build and run your first image

NOTEObjective — Build your first Docker image from a Dockerfile, run it, and understand the role of the .dockerignore file.
WARNINGBefore you begin — This lab assumes you have completed the previous modules. If you encounter name conflicts, ports already in use, or if Docker no longer responds correctly, use these commands to start from scratch:
bash
# Stop ALL running containers
docker stop $(docker ps -a -q)

# Remove ALL containers
docker rm $(docker ps -a -q)

# Remove ALL images (optional)
docker rmi $(docker images -q)

# Force removal if an image resists
docker rmi -f $(docker images -q)
⚠ Warning — These commands delete everything. Use them only if you want to start from a clean environment. The -f (force) option also removes images used by containers.

Learning objectives

TIPAt the end of this module — You will be able to master these essential skills.

Create the project

Step 1: Create the project folder

bash
mkdir ~/mon-premier-docker
cd ~/mon-premier-docker

Step 2: Create the Python script

Create a hello.py file:

bash
touch hello.py
nano hello.py

Paste this content, then save (Ctrl + O, Enter, Ctrl + X):

output
print("Hello from Docker!")
TIPQuick tip — You can create the file directly from the terminal:
bash
echo 'print("Hello from Docker!")' > hello.py

Check the file content:

bash
cat hello.py

Step 3: Create the Dockerfile

Create a file named Dockerfile (no extension):

bash
touch Dockerfile
nano Dockerfile

Paste this content, then save (Ctrl + O, Enter, Ctrl + X):

output
FROM python:3.11-slim
WORKDIR /app
COPY hello.py .
CMD ["python", "hello.py"]
go-further

This article covers the most useful excerpts — the complete Docker Containerization course (12 chapters, 41 lessons, corrected exercises and final project) takes you all the way.

./access-the-full-course free course: Mastering Claude Code

FAQ

How long does it take to learn Docker Containerization?
With a structured progression (12 chapters, 41 short and practical lessons), you reach an operational level in a few weeks at 30 to 60 minutes per day. The key is to practice each concept immediately.
Are there any prerequisites?
Basic computer knowledge is enough. If you can use a terminal and read simple code, you are ready.
Where to start concretely?
Reproduce the commands from this article, then follow the complete Docker Containerization course: it chains the 41 lessons in order, with exercises and a final project.

📬 Want to receive this type of guide every week? Subscribe for free — real code, zero fluff.