What is Docker and Why Use It?

Chapter 1 — What is Docker and Why Use It?

If you've ever set up a web server, a Python project, or a database and thought "this took ages — I never want to do this again", Docker is for you. Docker lets you package an application and everything it needs to run — the runtime, the libraries, the config — into a single portable unit called a container. You can start it in seconds, stop it cleanly, copy it to another machine, and it will behave exactly the same way every time.

In this chapter you'll understand what Docker actually is, how it differs from virtual machines, and get it installed and running your very first container.

1. The Problem Docker Solves

Picture this: you set up Apache on your Raspberry Pi. It works perfectly. A few months later your hosting provider's server has a slightly different OS version, different library versions, different PHP config — and suddenly things break in ways that are hard to debug. This is so common it has a name: "works on my machine".

Docker solves this by making the environment part of the application. Instead of installing Apache onto a server and hoping the server stays consistent, you run an Apache container that includes everything Apache needs. The server just needs Docker — nothing else.

The key idea: A container is not an app installed on your system. It is a self-contained environment that runs on top of your system, isolated from everything else, and portable to any machine running Docker.

2. Containers vs Virtual Machines

Both containers and virtual machines (VMs) solve the "consistent environment" problem, but they do it very differently — and the difference matters for everyday use.

Virtual Machine
Physical Hardware
Host OS (e.g. Ubuntu)
Hypervisor (VirtualBox / VMware)
Full Guest OS (Linux / Windows)
Binaries / Libraries
Your App
Boots a complete OS — slow to start, 1–20 GB per VM
Docker Container
Physical Hardware
Host OS (e.g. Ubuntu)
Docker Engine
Container (libs + config only)
Your App
Shares the host OS kernel — starts in seconds, MBs in size

A VM runs a complete operating system inside a hypervisor. It's powerful and fully isolated, but it takes minutes to boot and gigabytes of disk space. A Docker container shares the host's OS kernel and only packages what's different — the libraries and config your app needs. The result is a container that starts in one or two seconds and might be 50 MB instead of 10 GB.

  • Start time: VM = minutes. Container = seconds.
  • Disk space: VM = gigabytes. Container = megabytes.
  • Isolation: Both are isolated. Containers share the kernel but have their own filesystem, processes, and network.
  • Portability: Both are portable, but a Docker image moves far more easily than a VM disk file.
When would you still use a VM? When you need a completely different OS (e.g. running Windows on a Linux host), or when you need hardware-level isolation for security. For everything else — web servers, databases, development environments — Docker is faster and lighter.

3. Key Concepts

Docker has three core concepts you need to understand before anything else makes sense. Everything in Docker flows from these three ideas.

📦
Image
A read-only blueprint. An image contains the filesystem, libraries, and instructions needed to run an application. You don't run an image directly — you create a container from it.

Think of it like a cake recipe. The recipe itself isn't a cake.
🏃
Container
A running instance of an image. You can run many containers from the same image simultaneously, and each is independent.

Using the recipe analogy — a container is the actual cake you baked from it.
🏪
Registry
A place to store and share images. Docker Hub is the default public registry — it hosts official images for Apache, MySQL, Python, Node, and thousands more, free to pull and use.
⚙️
Docker Engine
The background service (daemon) that does all the work — pulling images, creating containers, managing networking and storage. You talk to it via the docker command.
Docker Hub
Registry
docker pull
downloads image
Image
on your machine
docker run
creates + starts
Container
running app

4. Installing Docker

On Windows (Docker Desktop)

Check your Windows version Docker Desktop requires Windows 10 64-bit (Build 19041+) or Windows 11. Open Settings → System → About to check. WSL 2 (Windows Subsystem for Linux) is the recommended backend — Docker Desktop installs it for you if needed.
Enable virtualisation in BIOS Virtualisation must be enabled. Most modern PCs have it on by default. Check Task Manager → Performance → CPU — if "Virtualization: Enabled" is shown, you're good. If not, enable it in your BIOS under CPU settings (Intel VT-x / AMD-V).
Download Docker Desktop Go to docker.com/products/docker-desktop and download the Windows installer. Run it and follow the prompts — it will install WSL 2 if needed and ask you to restart.
Start Docker Desktop After restarting, launch Docker Desktop from the Start menu. Wait for the whale icon in the taskbar to stop animating — that means the Docker engine is running. You won't need the Docker Desktop GUI much; most of the work is done in the terminal.

On Ubuntu / Debian Linux

# Remove any old Docker packages first sudo apt remove docker docker-engine docker.io containerd runc # Install prerequisites sudo apt update sudo apt install ca-certificates curl gnupg # Add Docker's official GPG key and repository sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list # Install Docker Engine sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin # Add your user to the docker group (avoids needing sudo every time) sudo usermod -aG docker $USER # Log out and back in, then verify: docker --version
Raspberry Pi users: Use the convenience script instead — curl -fsSL https://get.docker.com | sh — it handles the ARM architecture automatically. Then run sudo usermod -aG docker $USER and log back in.

On macOS

Download Docker Desktop from docker.com/products/docker-desktop, choose the correct version for your chip (Apple Silicon or Intel), and drag it to Applications. Start it and wait for the whale icon to settle in the menu bar.

5. Verifying the Install

Open a terminal (PowerShell on Windows, or any terminal on Linux/Mac) and run these two commands to confirm Docker is installed and the engine is running:

Terminal
$ docker --version Docker version 26.1.3, build b72abbb $ docker info Client: Docker Engine - Community Version: 26.1.3 ... Server: Docker Desktop Engine: Version: 26.1.3 ...

If docker info returns an error like "Cannot connect to the Docker daemon", the Docker engine isn't running. On Windows/Mac, make sure Docker Desktop is open. On Linux, start it with sudo systemctl start docker.

6. Your First Container

The traditional first Docker command pulls a tiny test image from Docker Hub and runs it. It's deliberately simple — but watch what actually happens:

Terminal
$ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 719385e32844: Pull complete Digest: sha256:4e83453afed1b... Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from Docker Hub. 3. The Docker daemon created a new container from that image, which runs the executable that produces this output. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal.

Notice what happened automatically:

  • Docker looked for the image locally — it wasn't there
  • Docker pulled it from Docker Hublibrary/hello-world is an official image
  • Docker created and ran a container from it — the container printed its message and exited
  • The container stopped — it finished its job, so it stopped. Containers only run as long as their process runs

Now try something slightly more interesting — run an interactive Ubuntu shell inside a container:

Terminal
$ docker run -it ubuntu bash Unable to find image 'ubuntu:latest' locally latest: Pulling from library/ubuntu ... root@a3f9c2d1e8b7:/# cat /etc/os-release NAME="Ubuntu" VERSION="24.04 LTS (Noble Numbat)" root@a3f9c2d1e8b7:/# exit $

You just ran a full Ubuntu environment, got a shell inside it, ran a command, and exited — all without installing Ubuntu on your machine. The two flags used here are important:

  • -i — interactive mode (keep STDIN open)
  • -t — allocate a terminal (so you get a proper shell prompt)

These are almost always used together as -it whenever you want to type commands inside a container.

7. What Happened Under the Hood

Every docker run command goes through the same sequence:

1. docker run ubuntu bash
you type this
The Docker client receives your command and passes it to the Docker daemon running in the background
2. Image check
local cache first
Daemon checks if the ubuntu image is already on your machine. If not, it pulls it from Docker Hub automatically
3. Container created
new writable layer
A new container is created from the image. A thin writable layer is added on top — your changes go here, the image itself stays unchanged
4. Process starts
bash in this case
The specified command (bash) runs inside the isolated container environment. When this process exits, the container stops
Images are layered and shared: If you run both ubuntu and a custom image built on top of ubuntu, they share the same underlying Ubuntu layers on disk. Docker only stores each layer once, which is why pulling a second Ubuntu-based image is much faster than the first.

8. Three Things to Remember About Containers

These three properties catch beginners out. Keep them in mind and a lot of Docker will make more sense:

  • Containers are ephemeral by default. When a container stops, any files written inside it are gone the next time you start a fresh container from the same image. This is intentional — containers are meant to be disposable. Chapter 4 covers how to persist data using volumes.
  • Each container has its own network. A web server running inside a container is not automatically accessible from your browser — you have to explicitly map a port from the container to your host. You'll see this in Chapter 5 and in the Apache scenario in Chapter 7.
  • The image is never modified by running it. No matter what you do inside a running container, the original image stays exactly as it was. Next time you create a container from that image, it starts fresh. To save changes into a new image, you write a Dockerfile (Chapter 6).
Exercises
  1. Run hello-world and read the output carefully. It tells you exactly the four steps Docker took to produce the message. Make sure you can explain each step in your own words.
  2. Run an interactive Ubuntu container with docker run -it ubuntu bash. Once inside, run apt update && apt install -y curl to install curl. Then exit the container and run a brand new docker run -it ubuntu bash — confirm that curl is no longer installed. This demonstrates that containers are ephemeral.
  3. Run an Alpine containerdocker run -it alpine sh (Alpine uses sh not bash). Alpine is a tiny Linux distro, very popular in Docker images. Check its size: exit the container and run docker images to compare the size of alpine vs ubuntu.
  4. List your images and containers: run docker images to see what you've pulled, and docker ps -a to see all containers including stopped ones. Notice that each docker run created a separate container even when using the same image.
  5. Clean up: remove all stopped containers with docker container prune and confirm with docker ps -a. This is a habit worth building — stopped containers don't use CPU or memory, but they do use a small amount of disk space.
Next: Chapter 2 — Images, Containers and the Docker Hub
Now that Docker is running, Chapter 2 goes deeper into images: how they're structured in layers, how to search and browse Docker Hub, how to pull specific versions with tags (nginx:1.27 vs nginx:latest), and how to manage the images and containers on your machine. You'll also run your first web server container and open it in a browser.