Module 1: Container Foundations
Why Containers Changed Everything
"It works on my machine" used to be one of the most expensive sentences in software. An application that ran perfectly on a developer's laptop would fail on the test server because of a different language version, a missing system library or a forgotten configuration file. Containers fixed this by packaging the application together with everything it needs to run, so that the same package behaves the same way everywhere. Understanding why that matters will help you use Docker well rather than just copying commands.
The deployment problem before containers
Imagine a small software company in Nairobi maintaining a school management system. It is written in Python, needs a specific version of a PDF library for report cards, and uses a system image-processing library for student photos. To deploy it, an engineer follows a long setup document on each server: install Python, install the right libraries, set environment variables, copy files, configure a process manager. Problems follow:
- Two schools' servers end up with slightly different library versions, and report cards render differently.
- Another application on the same server needs a newer Python, and upgrading it breaks the school system.
- Setting up a new developer's laptop takes a whole day.
- Rolling back a bad release means reversing manual changes from memory.
What a container is
A container is a normal process on a host machine that the operating system isolates so it sees its own filesystem, its own network interfaces, its own process list and limited resources. On Linux this isolation is built from kernel features: namespaces (separate views of processes, networking, mounts and hostnames) and control groups (cgroups, which limit CPU, memory and other resources). The filesystem the container sees comes from an image, a packaged, read-only snapshot of the application and its dependencies.
Docker made these kernel features easy to use. It gave developers a simple file format for describing images (the Dockerfile), a command-line tool for building and running them, and registries for sharing them. The image format was later standardised by the Open Container Initiative (OCI), so images you build with Docker also run on other compatible runtimes, including those used by Kubernetes.
Containers compared with virtual machines
| Virtual machine | Container | |
|---|---|---|
| What it includes | A full guest operating system with its own kernel | The application and its user-space dependencies; shares the host kernel |
| Typical size | Gigabytes | Megabytes to a few hundred megabytes |
| Start time | Usually tens of seconds or more | Usually around a second or less |
| Isolation | Strong, enforced by the hypervisor | Good, but weaker because the kernel is shared |
| Best for | Running different operating systems, strong tenant separation | Packaging and shipping applications consistently |
They are not rivals. In the cloud, containers usually run inside virtual machines. On Windows and macOS, Docker Desktop runs a small Linux virtual machine in the background so that Linux containers can run.
A worked example: the same app, two ways
Without containers, the school system's setup document might list fifteen steps. With Docker, the developer describes the environment once in a Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Then anyone, on any machine with Docker, runs two commands:
docker build -t school-system:1.0 .
docker run -d -p 8000:8000 school-system:1.0
The library versions are fixed inside the image, a second application can use a different Python in its own container without conflict, a new developer is productive in minutes, and rolling back means running the previous image tag. You will learn every line of this Dockerfile in the next module.
Why it changed the industry
- Consistency: the image that passed testing is exactly what runs in production.
- Density: many containers share one server efficiently.
- Speed: fast builds and starts make frequent releases practical.
- A common unit: build pipelines, cloud services and orchestrators such as Kubernetes all accept the same image format.
Common mistakes to avoid
- Treating a container like a small virtual machine, logging in to install software by hand. Changes belong in the Dockerfile, so the image can be rebuilt.
- Assuming containers are a full security boundary. They share the host kernel; you still need to follow security practices covered later.
- Storing important data inside the container. Containers are meant to be replaceable; data belongs in volumes.
Exercise
Pick an application you use or have built and list every step needed to run it on a fresh computer: language runtime and version, libraries, system packages, environment variables, ports and data locations. Mark which steps have caused problems for you or your team before. Keep this list, because it is the raw material for the Dockerfile you will write in Module 2.
Key points
- A container is an isolated process whose filesystem comes from an image.
- Linux namespaces and cgroups provide the isolation; Docker makes them easy to use.
- Containers share the host kernel, making them lighter but less isolated than virtual machines.
- Changes belong in the Dockerfile, not in hand edits to running containers.