Beyond "Docker Run"
When you run docker run nginx, a web server appears in seconds. No installation wizard, no dependency conflicts, no "works on my machine" problems. It feels like magic — but it's just Linux kernel features that have existed for over a decade, wrapped in a friendly interface.
Understanding Docker internals isn't just academic trivia. It's the difference between a developer who uses Docker and an engineer who can debug it, optimize it, and trust it in production. Concretely, this knowledge lets you build images that are:
- Smaller: Saving storage, reducing pull times, and speeding up deployments.
- Faster to build: Wasting less developer time waiting for CI pipelines.
- More secure: Reducing the attack surface of your applications.
- More predictable: Understanding why a container behaves unexpectedly under load or during shutdown.
At its core, a Docker container is not a virtual machine. It does not boot a separate kernel. It is a regular Linux process — or a group of processes — that the kernel has isolated from the rest of the system using two fundamental features:
- Namespaces: Control what a process can see. A container gets its own view of the process tree, network interfaces, filesystem mounts, hostname, and user IDs. From inside the container, it looks like a private machine. From outside, it's just a process.
- Control Groups (cgroups): Control what a process can use. CPU time, memory, disk I/O, and network bandwidth can all be capped per container.
These two primitives — namespaces for visibility isolation, cgroups for resource limitation — are the entire foundation of container technology. Docker is, at its heart, a user-friendly tool for configuring these kernel features and managing the filesystem images that go with them.
In this topic, we will explore how Docker manages files with layered filesystems, builds images efficiently with BuildKit, handles process lifecycles, and how you can use this knowledge to write better Dockerfiles today.