KAHIBARO
Discord Login Register

21.2. Docker Architecture

Big Picture of Docker Architecture

Docker is built with a client server architecture. Understanding how its pieces fit together will make everything else about containers much clearer.

There are three core parts:

Around these, there are additional pieces such as images, containers, networks, and volumes that you will use every day.

In this chapter we stay at the architecture level so you see how these parts talk to each other and where they run.


Docker Client

The Docker client is what you interact with directly. It is usually the docker command in your terminal.

Example commands:

bash
docker ps
docker run nginx:latest
docker build -t myapp:1.0 .

Key ideas:

You can think of the client as a REST API client for the Docker Engine API. It sends HTTP requests, receives HTTP responses, and prints human friendly output.

Example of pointing the client to a remote daemon:

bash
export DOCKER_HOST=tcp://my-server:2376
docker ps

The docker command is just one client. Docker also provides:

Docker Daemon (Server)

The Docker daemon is the long running background process that actually manages:

On most systems the main daemon process is dockerd.

Responsibilities:

A simple lifecycle when you run:

bash
docker run nginx:latest
  1. Client sends a request to the daemon:
    "Create a container from image nginx:latest and start it."
  2. Daemon checks if nginx:latest is available locally.
    • If not, it pulls the image from a registry.
  3. Daemon creates a container:
    • Sets up a filesystem from the image layers.
    • Configures network interfaces, ports, and environment variables.
    • Sets resource limits if requested.
  4. Daemon starts the container process.
  5. Daemon returns information to the client, which prints output.

The daemon can run:

Multiple clients can talk to the same daemon at the same time.

The daemon has root level access to the host by default.
If you expose the Docker daemon API over TCP without proper authentication and TLS, anyone who can connect to it can fully control the host.
Never expose the daemon publicly without strong protection.


Docker Engine and Components

The full system that includes the daemon and its low level container runtime is often called Docker Engine.

From top to bottom there are several layers.

High level architecture:

  1. Docker Client
  2. Docker Engine API
  3. Docker Daemon (dockerd)
  4. Container runtime (for example containerd, runc)
  5. Linux kernel features (namespaces, cgroups, union file systems)

You usually do not work with the lower layers directly, but knowing they exist helps when debugging.

Docker Engine API

The Engine exposes a REST API. Every docker command turns into HTTP calls, for example:

You can call this API directly from your own tools or backend services if you want to automate container operations.

Example, using curl to list containers on a Linux host:

bash
curl --unix-socket /var/run/docker.sock http://localhost/containers/json

Container Runtime

The daemon does not talk directly to the kernel. Instead it uses lower level runtimes.

Typical stack:

You rarely interact with these components directly in everyday backend work, but they explain how Docker can plug into other systems like Kubernetes.


Images and Layers

An image is an immutable blueprint from which containers are created.

Architecturally, images are made of layers. Each layer represents a filesystem change.

Example Dockerfile:

dockerfile
FROM python:3.12-slim          # Layer 1: base system + Python
WORKDIR /app                   # Layer 2: metadata change
COPY requirements.txt .        # Layer 3: adds file
RUN pip install -r requirements.txt   # Layer 4: installs packages
COPY . .                       # Layer 5: application code
CMD ["python", "main.py"]      # Metadata: default command

When you run:

bash
docker build -t myapp:1.0 .

The daemon:

  1. Reads the Dockerfile.
  2. Builds each instruction into a new layer.
  3. Stores layers in its local image store.
  4. Tags the final image as myapp:1.0.

Layers are stored in a union filesystem so they appear as a single filesystem to the container, but underneath they are stacked.

Important consequences:

Example:

The large base and dependency layers are shared. Only the final app code layer differs.

Important rule: Images are immutable.
After an image is built, you do not change it. You build a new image instead, usually with a new tag such as myapp:1.1.
This immutability is a core part of reliable deployments.


Containers as Running Instances

A container is a running instance of an image plus some runtime configuration.

Relationship:

When the daemon creates a container:

  1. It takes the image layers.
  2. Adds a thin writable layer on top.
  3. Starts the process defined by CMD or ENTRYPOINT.
  4. Applies isolation:
    • Namespaces for process IDs, network, mounts, etc.
    • Control groups (cgroups) for CPU and memory limits.

From inside the container, the process sees:

From outside, you can inspect containers:

bash
docker ps           # list running containers
docker inspect ID   # show full configuration and state

Think of a container as:

Registries and Repositories

A registry is a server that stores and distributes images.
A repository is a collection of related image tags under a name in a registry, for example library/nginx.

Public registry example:

Private registry examples:

Flow when you use docker pull:

  1. Client: docker pull nginx:latest.
  2. Daemon: Contacts the registry (Docker Hub by default).
  3. Registry: Authenticates the user if needed.
  4. Registry: Sends metadata and layers to the daemon.
  5. Daemon: Stores the image locally.

Flow when you use docker push:

  1. Daemon: Sends image layers to the registry.
  2. Registry: Stores layers and tags them.

Naming convention:

Examples:

Example image nameMeaning
nginxlibrary/nginx:latest on default registry
nginx:1.25nginx 1.25 tag on default registry
myuser/myapp:1.0User myuser repository myapp on default registry
ghcr.io/myorg/api:prodHosted on GitHub Container Registry for myorg

Registries are critical in backend deployment because they are the bridge between your build pipeline and your production servers.


Storage: Volumes and Bind Mounts

Docker needs to store:

By default, the writable layer inside a container disappears when the container is removed. For persistent data you use:

These are not separate daemon processes, but conceptually they form a storage layer in the architecture.

Example: named volume

bash
docker volume create mydata
docker run -d \
  -v mydata:/var/lib/postgresql/data \
  --name mydb postgres:16

Example: bind mount (useful in development)

bash
docker run --rm -it \
  -v $(pwd):/app \
  -w /app \
  python:3.12-slim python main.py

Architectural idea:

Networking and Communication

From an architecture perspective, Docker networking solves two main needs:

  1. Containers talking to each other.
  2. Containers exposing services to the outside world.

Docker daemon manages different network drivers. Three common ones:

Network typeDefault nameTypical use
bridgebridgeDefault for standalone containers
hosthostContainer shares host network namespace
nonenoneNo network connectivity

With user defined bridge networks, Docker also provides:

Example:

bash
docker network create backend-net
docker run -d --name db --network backend-net postgres:16
docker run -d --name api --network backend-net my-api:1.0

Inside api container, connecting to db:5432 works because Docker provides an internal DNS entry.

To expose a container to the outside, the daemon sets up port mappings:

bash
docker run -d -p 8080:80 --name web nginx

Here:

Putting It All Together: End to End Example

Consider a typical backend workflow.

You:

  1. Write code and a Dockerfile for your FastAPI application.
  2. Run docker build -t myorg/myapi:1.0 .
  3. Run tests, then docker push myorg/myapi:1.0 to a registry.
  4. On a production server, you run docker pull myorg/myapi:1.0.
  5. You start the app with docker run -d -p 80:8000 myorg/myapi:1.0.

Under the hood:

Every time you use Docker in backend development, you are using this architecture: a client talking to a daemon, which orchestrates images, containers, networks, volumes, and registries.

Understanding this structure will help you when you:

Views: 6

Comments

Please login to add a comment.

Don't have an account? Register now!