Docker Architecture

Understand the Docker client, dockerd daemon, containerd, runc, registries, and the Linux kernel features that make containers work.

Docker uses a client-server architecture. The docker command you type is only a client; the real work is done by a background service called the Docker daemon, which in turn delegates to lower-level runtime components. Knowing who does what helps you debug problems, understand what happens on docker run, and answer architecture questions in interviews.

The Big Picture

 docker CLI  ──REST API──►  dockerd (Docker daemon)  ──►  containerd  ──►  runc  ──►  container process
 (client)    (unix socket)   images, networks, volumes      lifecycle        creates     (namespaces + cgroups)
                                   │
                                   └──► Registry (Docker Hub, private registry)

Main Components

Component Role
Docker client (docker) Command-line tool that sends API requests to the daemon
Docker daemon (dockerd) Long-running service that manages images, containers, networks, and volumes
containerd High-level container runtime: image transfer, storage, container lifecycle
runc Low-level OCI runtime that actually creates the container process
Registry Stores and serves images (Docker Hub, GitHub Container Registry, a private registry)
Docker objects Images, containers, networks, volumes, plugins

Docker Client

The client talks to the daemon over a REST API. By default on Linux it uses the Unix socket /var/run/docker.sock; it can also connect to a remote daemon over TCP or SSH. The same API is used by Docker Compose, IDE plugins, and CI tools.

# The CLI is just one API consumer. You can call the API directly:
curl --unix-socket /var/run/docker.sock http://localhost/version

Docker Daemon (dockerd)

dockerd listens for API requests and manages Docker objects: it builds images (using BuildKit), creates networks and volumes, and asks containerd to run containers.

containerd and runc

containerd manages the complete container lifecycle on the host (pulling and storing images, starting and stopping containers). It uses runc, a reference implementation of the OCI (Open Container Initiative) runtime specification, to create the isolated process. Because of the OCI standards, images and runtimes from different vendors are interchangeable. Kubernetes, for instance, can use containerd directly without dockerd.

Registry

A registry stores images in repositories identified by name and tag. Docker Hub is the default; docker pull nginx is shorthand for docker pull docker.io/library/nginx:latest.

What Happens on docker run

docker run -d -p 8080:80 nginx:1.27
  1. The client sends a create-and-start request to dockerd.
  2. dockerd checks for nginx:1.27 locally; if absent, it pulls the layers from the registry.
  3. The image layers are stacked with a union filesystem and a thin writable layer is added.
  4. A network interface is created and attached to the default bridge network; port 8080 on the host is forwarded to port 80.
  5. containerd and runc create the process inside new namespaces and cgroups.
  6. The image's default command (nginx -g 'daemon off;') starts as the container's main process.

Kernel Features Behind Containers

Feature Purpose
Namespaces (pid, net, mnt, uts, ipc, user) Isolate what the process can see
Control groups (cgroups) Limit and account for CPU, memory, and I/O
Union filesystem (overlay2) Stack read-only image layers with a writable top layer
Capabilities, seccomp, AppArmor/SELinux Restrict privileges and system calls

You can see these limits in action:

docker run -d --name limited --memory 256m --cpus 0.5 nginx:1.27
docker stats --no-stream limited
# CONTAINER ID   NAME      CPU %   MEM USAGE / LIMIT   MEM %   ...
# 7c1d0e9a3b52   limited   0.00%   5.5MiB / 256MiB     2.15%

Inspecting Your Installation

docker version        # client and server versions
docker info           # storage driver, cgroup version, number of containers/images, runtimes
docker context ls     # which daemon the CLI is currently talking to
docker system df      # disk used by images, containers, volumes, build cache

docker info shows Storage Driver: overlay2 on most Linux systems and lists the default runtime (runc).

Docker Desktop

On macOS and Windows, containers still need a Linux kernel. Docker Desktop runs a lightweight Linux VM that hosts the daemon, and the docker CLI on your host talks to it. This is why bind-mount performance and localhost behaviour can differ from native Linux.

Common Mistakes

  • Assuming the CLI runs containers. The client only sends requests; if the daemon is down you get "Cannot connect to the Docker daemon".
  • Exposing the daemon over unauthenticated TCP. Anyone who can reach the API effectively has root on the host. Use the Unix socket, SSH, or TLS.
  • Mounting /var/run/docker.sock into containers casually. Access to the socket is equivalent to root access to the host.
  • Confusing Docker with the OCI runtime. Docker is a toolchain built on containerd and runc; the runtime is replaceable.

Best Practices

  • Keep the Docker Engine updated for security fixes.
  • Restrict access to the Docker group and the daemon socket.
  • Use docker context to switch between local and remote daemons explicitly.
  • Monitor disk usage with docker system df and prune regularly on build servers.

Interview Questions

1. Explain Docker's architecture.

Docker uses a client-server model. The docker CLI sends REST API calls to the dockerd daemon, which manages images, containers, networks, and volumes. The daemon delegates container lifecycle management to containerd, which uses runc to create containers. Images are pulled from and pushed to a registry.

2. What is the role of containerd and runc?

containerd is the high-level runtime that manages image storage and container lifecycle. runc is the low-level OCI runtime that sets up namespaces and cgroups and starts the process. Splitting these layers makes components replaceable and standards-based.

3. How does Docker isolate containers?

Through Linux namespaces (isolating processes, network, mounts, hostname, IPC, and users) and cgroups (limiting CPU, memory, and I/O). Capabilities, seccomp profiles, and AppArmor or SELinux further restrict what the process can do.

4. What is a union filesystem and why does Docker use it?

It overlays several read-only layers and one writable layer into a single view. Docker uses overlay2 so that layers can be shared between images and containers, saving disk space and making pulls and builds faster.

5. How does the Docker client communicate with the daemon?

Via the Docker Engine REST API, by default through the Unix socket /var/run/docker.sock. It can also use TCP with TLS or SSH, selected through DOCKER_HOST or a Docker context.

6. Why is mounting docker.sock into a container dangerous?

A process with access to the socket can ask the daemon to start privileged containers and mount the host filesystem. That gives it root-equivalent control of the host.

Summary

  • The docker CLI is a client; dockerd does the work and delegates to containerd and runc.
  • Containers are ordinary Linux processes isolated by namespaces and limited by cgroups.
  • Images are stacked layers served by a union filesystem such as overlay2.
  • The daemon socket is a high-privilege interface and must be protected.

Continue Learning

Previous: Docker Introduction | Next: Dockerfile Basics

Was this guide helpful?

CodeWithVenu is free to read, with no paywall. If this guide saved you time or helped you prepare, a small voluntary contribution helps me write more practical tutorials, architecture guides, and interview-prep content.