Docker Architecture
Understanding Docker's architecture helps you work more effectively with containers and troubleshoot issues. Docker uses a client-server architecture with several key components.
High-Level Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Docker Client │
│ (docker CLI, API) │
└─────────────────────────┬───────────────────────────────────────┘
│ REST API
▼
┌─────────────────────────────────────────────────────────────────┐
│ Docker Daemon │
│ (dockerd) │
├─────────────┬─────────────────┬─────────────┬───────────────────┤
│ Images │ Containers │ Networks │ Volumes │
└─────────────┴─────────────────┴─────────────┴───────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Container Runtime │
│ (containerd) │
└─────────────────────────────────────────────────────────────────┘
Core Components
Docker Client
The Docker client is what you interact with directly. When you run commands like docker run or docker build, the client sends these commands to the Docker daemon.
Key characteristics:
- Primary interface for users
- Can connect to local or remote Docker daemons
- Communicates via REST API over Unix socket or network
# The docker CLI is the client
docker ps
docker images
docker run nginx
Docker Daemon (dockerd)
The daemon is the heart of Docker. It runs in the background and manages Docker objects like images, containers, networks, and volumes.
Responsibilities:
- Listening for Docker API requests
- Managing Docker objects
- Communicating with other daemons for swarm services
Docker Registry
Registries store Docker images. Docker Hub is the default public registry, but you can run private registries.
Docker Hub (Public) Private Registry
┌───────────────┐ ┌───────────────┐
│ nginx:latest │ │ myapp:v1.0 │
│ redis:alpine │ │ mydb:latest │
│ node:18 │ │ api:prod │
└───────────────┘ └───────────────┘
Docker Objects
Images
Images are read-only templates used to create containers. They're built in layers, with each layer representing a set of filesystem changes.
┌─────────────────────┐
│ Application │ Layer 4: Your app
├─────────────────────┤
│ Dependencies │ Layer 3: npm install
├─────────────────────┤
│ Node.js │ Layer 2: Runtime
├─────────────────────┤
│ Alpine Linux │ Layer 1: Base OS
└─────────────────────┘
Containers
Containers are runnable instances of images. They're defined by the image plus any configuration options you provide when creating or starting them.
Container properties:
- Isolated process space
- Own filesystem (from image layers + writable layer)
- Own network interface
- Resource limits (CPU, memory)
Networks
Docker networking allows containers to communicate with each other and the outside world.
┌─────────────────────────────────────────┐
│ Docker Host │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Web App │ │ API │ │Database │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ └────────────┼────────────┘ │
│ ┌─────┴─────┐ │
│ │ Bridge │ │
│ │ Network │ │
│ └───────────┘ │
└─────────────────────────────────────────┘
Volumes
Volumes persist data beyond the container lifecycle. They're managed by Docker and stored outside the container's filesystem.
┌─────────────────────────────────────────┐
│ Container │
│ ┌─────────────────────────────────┐ │
│ │ Container Filesystem │ │
│ │ /var/lib/mysql ──────────────────┐ │
│ └─────────────────────────────────┘ │ │
└───────────────────────────────────────│─┘
│
┌───────────────────────────────────────│─┐
│ Volume │ │
│ /var/lib/docker/volumes/mysql-data │ │
│ ◄───────────────────────────┘ │
└─────────────────────────────────────────┘
The Container Runtime
Docker uses containerd as its container runtime. The relationship is:
Docker CLI → Docker Daemon → containerd → runc → Container
containerd
- Manages the complete container lifecycle
- Image transfer and storage
- Container execution and supervision
runc
- Low-level container runtime
- Creates and runs containers
- Implements the OCI (Open Container Initiative) specification
Image Layers in Detail
Images are built using a Union File System that stacks layers:
# Each Dockerfile instruction creates a layer
FROM node:18-alpine # Layer 1: Base image
WORKDIR /app # Layer 2: Metadata change
COPY package.json . # Layer 3: Add package.json
RUN npm install # Layer 4: Install dependencies
COPY . . # Layer 5: Add application code
CMD ["node", "app.js"] # Layer 6: Default command
Layer benefits:
- Caching: Unchanged layers are reused
- Sharing: Multiple images can share base layers
- Efficiency: Only changed layers are downloaded/uploaded
Docker Communication Flow
When you run docker run nginx:
- Client sends request to daemon via Unix socket
- Daemon checks if
nginximage exists locally - Daemon pulls image from registry if needed
- Daemon instructs containerd to create container
- containerd uses runc to start the container process
- Container runs with isolated namespaces and cgroups
User Input Docker Operations
────────── ─────────────────
docker run nginx → 1. Parse command
2. Check local images
→ 3. Pull from registry (if needed)
4. Create container
→ 5. Start container process
Container running ← 6. Return container ID
Linux Kernel Features
Docker relies on several Linux kernel features:
Namespaces (Isolation)
- PID: Process isolation
- NET: Network isolation
- MNT: Filesystem isolation
- UTS: Hostname isolation
- IPC: Inter-process communication isolation
- USER: User ID isolation
cgroups (Resource Limiting)
- CPU allocation
- Memory limits
- I/O bandwidth
- Network bandwidth
Union Filesystem
- Overlay2 (default on modern Linux)
- Enables layered images
Key Takeaways
- Docker uses a client-server architecture
- The Docker daemon manages all Docker objects
- Images are read-only templates built in layers
- Containers are running instances of images with a writable layer
- containerd and runc handle low-level container operations
- Linux namespaces provide isolation; cgroups limit resources
- Understanding architecture helps with troubleshooting and optimization

