Intro & Concepts — Module Overview
Why Docker?
Section titled “Why Docker?”Every developer has heard it: “It works on my machine.” The application runs perfectly in development, then breaks in staging or production because of a different OS, a mismatched library version, or a missing environment variable. Docker narrows that gap by packaging your application together with everything it needs — the runtime, dependencies, and configuration — into a single, portable unit called a container.
With Docker you get:
- Consistent environments — the same image runs the same userland on a laptop, a CI server, and a cloud VM (the kernel underneath is still the host’s, see Containers vs VMs).
- Isolation — each container has its own filesystem view and process space, so applications do not interfere with each other.
- Speed — no guest OS to boot. Measured below: a warm
docker runfinishes in about a quarter of a second. - Reproducibility — a
Dockerfileis a precise recipe; building it against the same pinned base image and inputs gives the same result.
What this module covers
Section titled “What this module covers”| Lesson | What you will learn |
|---|---|
| This page | Problems Docker solves, first container, real timings |
| What is Docker? | Architecture: client, daemon, images, registries — proven over the real socket |
| Containers vs VMs | Kernel sharing, namespaces, cgroups — proven with uname, /proc and memory.max |
| Install & Verify | Installing Docker, verifying installation, the docker group |
| Your First Container | Interactive + detached containers, docker ps, docker stop and the 10-second timeout |
Versions used in this course
Section titled “Versions used in this course”Every command and every output block in this course was run on one machine, on 2026-09-30:
| Component | Version (from docker version / docker compose version) |
|---|---|
| Docker Desktop | 4.81.0 (macOS, Apple Silicon, linux/arm64) |
| Docker Engine | 29.6.1 (API 1.55, minimum 1.40) |
| containerd / runc | v2.2.5 / 1.3.6 |
| Buildx / BuildKit | v0.35.0-desktop.2 / v0.31.1 |
docker compose plugin | v5.3.0 (there is no separate docker-compose binary and no “Compose v2” any more) |
Outputs are pasted as they came out of this Mac. Where Linux Engine behaves differently, a callout says so. Image sizes are arm64 sizes; amd64 sizes differ a little.
Your first container
Section titled “Your first container”The fastest way to confirm Docker is working is the official hello-world image. Docker pulls the image from Docker Hub if it is not cached locally, starts a container, prints a message, and exits.
docker run hello-worldTry it now using the interactive playground below:
docker run hello-worldHow fast is “fast”? Measured
Section titled “How fast is “fast”? Measured”Timing three runs of a container that does nothing (true exits immediately), image already present, on this Mac (wall clock including the CLI start-up and the round trip into the VM):
$ docker run --rm alpine:3.24 true # 0.25 s$ docker run --rm alpine:3.24 true # 0.24 s$ docker run --rm alpine:3.24 true # 0.25 sAnd a truly cold start — image not on disk, so it includes the pull from Docker Hub (docker rmi hello-world first):
$ docker run --rm hello-world # 4.21 s (mostly the network pull)$ docker run --rm hello-world # 0.25 s (warm)So “milliseconds” in marketing means: creating the namespaces and cgroups and exec-ing the process is cheap, and there is no kernel to boot. What you actually wait for is the pull (first time) and your own application’s start-up. A VM has to boot a whole guest kernel and init system before your process even starts; that difference is the point, not the exact number.
Where the pieces run on a Mac
Section titled “Where the pieces run on a Mac”flowchart LR
subgraph MAC["macOS (your Mac)"]
cli["docker CLI (darwin/arm64)"]
sock["~/.docker/run/docker.sock"]
end
subgraph VM["Docker Desktop Linux VM (linuxkit kernel)"]
engine["dockerd + containerd + runc"]
c1["your containers (linux/arm64)"]
end
cli --> sock --> engine --> c1 Reading AI-generated code
Section titled “Reading AI-generated code”AI assistants write plausible “is Docker ready?” checks. This one is used at the top of many CI and setup scripts:
🐛 Spot the bug
#!/bin/sh# AI: "verify that Docker is installed and running before the build"if docker --version; thenecho "Docker is ready"docker build -t myapp:ci .fiShow the answer
docker --version only asks the client binary for its version, which is why it works even when no daemon is reachable. Proven here by pointing the CLI at a socket that does not exist:
$ DOCKER_HOST=unix:///nonexistent.sock docker --versionDocker version 29.6.1, build 8900f1d$ echo $?0$ DOCKER_HOST=unix:///nonexistent.sock docker version --format '{{.Server.Version}}'failed to connect to the docker API at unix:///nonexistent.sock; check if the path is correct and if the daemon is running: dial unix /nonexistent.sock: connect: no such file or directory$ echo $?1The script prints “Docker is ready” and only then fails on the docker build, with a misleading log. Ask the server something instead — docker info or docker version --format both exit non-zero when the daemon is unreachable:
#!/bin/shset -euif ! docker info >/dev/null 2>&1; then echo "Docker daemon is not reachable (is Docker Desktop running?)" >&2 exit 1fiecho "Docker is ready: $(docker version --format '{{.Server.Version}}')"Mental Model
Section titled “Mental Model”Think of Docker as three things stacked: a client that turns your commands into API calls, an engine that owns images, containers, networks and volumes, and the Linux kernel that actually isolates processes. A container is not a small computer; it is a normal Linux process that the kernel has been told to show a private view of the filesystem, network and process table. That is why it starts in about a quarter of a second, and why it can never be faster than the process inside it.
Trade-offs
Section titled “Trade-offs”| Choice | Benefit | Cost |
|---|---|---|
| Containers instead of “install on the host” | Same image everywhere, clean throw-away environments | You now operate an engine, images and a registry |
| Docker Desktop on Mac/Windows | One installer gives you CLI, engine, Compose, Buildx | Engine runs in a VM: extra RAM, file-sharing overhead, bridge IPs not reachable from the host |
| Pulling from Docker Hub on first run | Zero setup | Cold start costs seconds and counts against pull rate limits |
Common Misconceptions
Section titled “Common Misconceptions”- “A container starts in milliseconds.” The isolation set-up is cheap, but measured end-to-end it was 0.25 s warm and 4.21 s cold here. Your application’s own start-up usually dominates.
- “Docker guarantees identical behaviour everywhere.” The image is identical; the kernel, CPU architecture (
arm64here) and host settings are not. Anamd64-only image runs under emulation on Apple Silicon. - “
docker --versionproves Docker works.” It only proves the client is installed. Usedocker info.