🚀 Introduction
Docker revolutionized the way applications are built, shipped, and run.
But beyond the buzzwords, few truly understand how Docker works under the hood — how a simple command like
docker run nginx
translates into a fully isolated process running inside a container.
This article takes you deep into Docker’s architecture, layer by layer — from the Docker CLI all the way down to Linux kernel namespaces and cgroups.
đź§© 1.What Is Docker?
Docker is an open-source containerization platform that packages an application and all its dependencies into a single unit called a container.
Containers ensure that applications run consistently across environments — whether it’s a developer’s laptop, an on-prem server, or a cloud VM.
At its core, Docker is a set of components working together:
Docker CLI → dockerd (Docker Daemon) → containerd → runc → Linux Kernel
Let’s decode each component in order.
🧰 2.Docker CLI – The User Interface
The Docker CLI (docker command) is the entry point for interacting with the Docker Engine.
Key Functions:
Accepts user commands (docker build, docker run, docker ps).
Sends them to the Docker Daemon via the Docker REST API over a Unix socket (/var/run/docker.sock).
When you run:
docker run nginx
You’re not directly running a container — you’re sending a JSON API request to the daemon.
CLI → Daemon communication:
/usr/bin/docker → /var/run/docker.sock → dockerd
⚙️ 3.Docker Daemon (dockerd) – The Brain
The Docker Daemon is the central control service of the Docker Engine.
It runs in the background, constantly listening for API requests from the CLI or other clients.
Key Responsibilities:
Build and manage Docker images.
Manage containers, networks, and volumes.
Handle authentication with registries (e.g., Docker Hub, JFrog, AWS ECR).
Communicate with containerd for container lifecycle management.
In essence, dockerd is the orchestrator that translates high-level user intent into low-level container actions.
Command to check if it’s running:
sudo systemctl status docker
⚙️ 4.containerd – The Runtime Manager
Originally a part of Docker, containerd is now a standalone CNCF project.
It’s the core container runtime interface used not only by Docker but also by Kubernetes.
Purpose:
containerd manages the entire lifecycle of a container:
Pulling/pushing images
Managing snapshots (layered filesystems)
Creating, starting, stopping, and deleting containers
Exposing an API for higher-level systems (like dockerd or Kubernetes)
When dockerd receives a command like “create a container,” it delegates that request to containerd.
containerd then invokes a low-level runtime (runc) to create the actual container process.
You can see it running:
ps aux | grep containerd
🧩 5.containerd-shim – The Silent Middle Layer
Each running container is managed by a small process called the containerd-shim.
Why It Exists:
Keeps containers running even if containerd or dockerd crashes.
Maintains the container’s STDIN/STDOUT streams.
Reaps zombie processes (acts as the parent process of the container).
So the runtime stack looks like this:
dockerd → containerd → containerd-shim → runc
⚙️ 6.runc – The Low-Level Runtime (The Actual Container Creator)
runc is the OCI (Open Container Initiative) compliant runtime responsible for actually creating containers.
It’s a lightweight binary that calls Linux kernel features to provide isolation.
What It Does:
Uses the clone() syscall to create a new process with isolated namespaces.
Applies cgroups for CPU, memory, and I/O limits.
Mounts the root filesystem using OverlayFS layers.
Executes the container’s default command (/bin/sh, nginx, etc.).
Then exits — leaving the container process running independently.
After container creation:
runc terminates.
The container continues running under containerd-shim.
🧠7.Linux Kernel – The Real Workhorse
All the above components (dockerd, containerd, runc) are user-space tools.
The Linux kernel provides the fundamental mechanisms that make containers possible:
Kernel Feature Purpose
Namespaces Isolate processes, networks, filesystems, users, etc.
cgroups Control and limit CPU, memory, and I/O usage.
Capabilities Restrict root privileges.
OverlayFS / UnionFS Combine multiple image layers into a single root filesystem.
đź§± 8.Namespaces Explained (Isolation Layer)
Namespaces create isolated environments for each container.
Every container gets its own unique instance of several namespaces:
PID: Process IDs Each container has its own PID 1
NET: Network stack Own IP, interfaces, routing tables
MNT: Filesystem mounts Separate root filesystem
IPC: Inter-process communication Own shared memory
UTS: Hostname/domain Custom hostname
USER: User IDs Root inside container ≠root on host
Check namespaces on a container:
ls /proc//ns
🔒 9.Control Groups (cgroups) – Resource Management Layer
While namespaces isolate, cgroups control.
They limit and monitor a container’s access to CPU, memory, block I/O, and network.
Example:
docker run --memory=512m --cpus=1 nginx
This enforces kernel-level resource limits using cgroups.
đź§© 10.The Full Execution Flow
Let’s connect everything together visually 👇
$ docker run nginx
│
├── Docker CLI
│ → Sends REST API to /var/run/docker.sock
│
├── Docker Daemon (dockerd)
│ → Parses config, checks image, calls containerd
│
├── containerd
│ → Manages lifecycle, sets up filesystem
│
├── containerd-shim
│ → Keeps container alive, manages IO
│
├── runc
│ → Creates container via kernel syscalls (clone, mount, setns)
│
├── Linux Kernel
│ → Enforces isolation (namespaces, cgroups)
│
└── Container
→ A running isolated process
🔍 11.Why Docker Split into These Components
Originally, Docker was monolithic — one big daemon handling everything.
To align with open standards and improve reliability, Docker adopted a modular runtime model based on OCI and CNCF specifications.
Layer Component Standard
High-level Docker Engine Docker API
Runtime manager containerd CNCF project
Low-level runtime runc OCI Runtime Spec
This modularity made it possible for Kubernetes to use containerd + runc directly, even without Docker.
⚡ 12.The Kernel-Primitives View
Ultimately, containers are just Linux processes with:
Isolated namespaces
Restricted resources via cgroups
Controlled capabilities
A layered filesystem
So docker run is essentially a user-friendly abstraction over a series of Linux system calls orchestrated by runc.
🧠13.Recap – The Docker Architecture Hierarchy
Layer Component Role Runs In
1 Docker CLI Command interface User space
2 Docker Daemon (dockerd) API, orchestration User space
3 containerd Container lifecycle management User space
4 containerd-shim Process supervisor User space
5 runc Container creator User space → kernel
6 Linux Kernel Isolation (namespaces, cgroups) Kernel space
đź§© 14.Conclusion
Docker isn’t magic — it’s an elegant orchestration of Linux primitives wrapped in developer-friendly tooling.
Understanding its internal architecture gives you control over:
Performance tuning
Security hardening
Runtime debugging
Building your own container-based systems
When you think in terms of CLI → Daemon → containerd → runc → Kernel → Namespaces,
you’re no longer “using Docker” — you’re engineering with it.
Top comments (0)