Docker Fundamentals and the Magic Behind Containers

Main concepts of Docker, and how is works under the hood.

October 31, 2025 · 5 min read

#Introduction

Going back to the roots of Docker gave me a deep understanding on how virtualization actually works.

When I started diving into Docker as part of my DevOps learning journey, I thought I’d just learn some commands and be done with it. Boy, was I wrong. The more I dug into how Docker actually works under the hood, the more fascinated I became with the elegant engineering that makes containerization possible.

Before we talk about Docker, let’s talk about why it exists. Remember the classic developer excuse: “But it works on my machine!”? That’s the problem Docker solves. Applications used to be tightly coupled with their environments, making deployment a nightmare. Virtual machines were one solution, but they’re heavy — each VM needs its own operating system, eating up gigabytes of space and precious resources.

Containers changed everything. They’re lightweight, portable, and share the host’s kernel while maintaining isolation. But here’s the thing that blew my mind: Docker didn’t invent containers. It just made them accessible to mere mortals like us.

Docker is essentially a user-friendly wrapper around Linux containers (LXC). The real magic happens at the Linux kernel level, where three key technologies work together to create what we call a container.

The first piece of the puzzle is namespaces. Think of namespaces as creating alternate realities for your processes. When a process runs in a container, it thinks it’s alone in the world. It has its own view of the system, completely isolated from other processes.

Linux provides several types of namespaces, and each one isolates a different aspect of the system. The PID namespace gives each container its own process tree — process ID 1 in your container isn’t the same as PID 1 on your host. The network namespace provides isolated network interfaces, routing tables, and firewall rules. There’s also the mount namespace for filesystems, the UTS namespace for hostname and domain name, and a few others.

What really clicked for me was realizing that these aren’t virtual resources — they’re just different views of the same physical resources. It’s like looking at the same building through different windows; each window shows a different perspective, but it’s still the same building.

While namespaces handle isolation, control groups (cgroups) handle resource management. This is how Docker ensures one container doesn’t hog all your CPU or memory and starve the others.

Cgroups allow you to set limits on CPU usage, memory consumption, disk I/O, and network bandwidth. But they do more than just set limits — they also monitor and report resource usage. This is how you can run docker stats and see exactly how much memory and CPU each container is consuming.

I found it fascinating that cgroups work hierarchically. You can create groups within groups, each with their own resource limits. Docker leverages this to give you fine-grained control over container resources. Want to limit a container to 512MB of RAM and 50% of one CPU core? Cgroups make it happen.

The third pillar of container technology is the union filesystem, and this is where Docker’s innovation really shines. Union filesystems allow you to overlay multiple filesystems on top of each other, creating a single, unified view.

Here’s where it gets clever: Docker images are built in layers, and each layer represents a change to the filesystem. When you write a Dockerfile with multiple instructions, each instruction creates a new layer. These layers are read-only and cacheable.

When you run a container, Docker adds a thin, writable layer on top of all the image layers. This is where any changes you make inside the container are stored. The beauty of this system is that multiple containers can share the same underlying image layers — they only differ in their thin writable layers on top.

This layering system is why pulling Docker images is so efficient. If you already have some layers from a previous image, Docker only downloads the layers you’re missing. It’s also why Docker images can be surprisingly small despite containing entire application stacks.

What Docker did brilliantly was take these powerful but complex Linux kernel features and wrap them in a developer-friendly package. The Docker daemon manages all the complexity of creating namespaces, setting up cgroups, and managing union filesystems. All you need to do is run docker run, and Docker orchestrates everything behind the scenes.

Docker also introduced the Dockerfile, a simple text file that describes how to build an image. This was revolutionary because it made infrastructure reproducible and version-controllable. Your entire application environment could now be defined as code, checked into Git, and built automatically.

As I worked through this section of the DevOps roadmap, I had several “aha!” moments that really solidified my understanding:

Containers aren’t virtual machines. They don’t virtualize hardware; they virtualize the operating system. This is why they’re so lightweight and start so quickly.

Everything is a process. A container is just a process (or group of processes) running on your host machine, but with a restricted view of the system thanks to namespaces and cgroups.

Layers are immutable. Once a layer is created, it never changes. When you modify a file in a container, you’re not changing the original layer — you’re creating a new entry in the writable layer that masks the original.

The kernel is shared. All containers on a host share the same Linux kernel. This is why you can’t run Windows containers on a Linux host (without virtualization) and why container security is so important.

You might wonder why understanding these low-level details matters when Docker abstracts them away so nicely. For me, knowing how things work under the hood has made me a better DevOps engineer. When something goes wrong, I can reason about what might be happening. When I need to optimize performance or security, I understand what levers I can pull.

More importantly, understanding these fundamentals helps you appreciate the elegance of the solution. Containers aren’t some magical new technology — they’re a clever combination of existing Linux features, packaged in a way that revolutionized how we build and deploy software.

This deep dive into Docker fundamentals has given me a solid foundation for the rest of my DevOps journey. Understanding namespaces, cgroups, and union filesystems isn’t just academic knowledge — it’s the bedrock that everything else builds upon.

Next up on the roadmap: container orchestration with Kubernetes. Armed with this understanding of how containers actually work, I’m excited to learn how Kubernetes manages them at scale. But that’s a story for another post.


This is part 002 of my Zero to DevOps series, where I document my learning journey through the DevOps roadmap. Follow along as I explore each technology in depth, sharing the insights and “aha!” moments along the way.

Share this article