Docker Architecture

Week 11: Docker and Containerization - Monday Lecture 2

Introduction to Docker Architecture

In our previous lecture, we explored the fundamental concepts of containers and how they revolutionize application deployment. Now, we'll dive deeper into Docker's architecture - the components that work together to create, run, and manage containers efficiently.

Understanding Docker's architecture is like understanding how a car works under the hood. While you can drive a car without knowing all its internal mechanics, understanding these components helps when you need to troubleshoot problems, optimize performance, or customize your experience.

graph TB subgraph "Docker Architecture Overview" A[Docker Client] -->|Commands| B[Docker Daemon] B -->|Manages| C[Containers] B -->|Builds & Uses| D[Images] E[Registry] -->|Provides| D B -->|Uses| F[Networks] B -->|Uses| G[Volumes] end style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px style E fill:#fdebd0,stroke:#333,stroke-width:2px style F fill:#d6eaf8,stroke:#333,stroke-width:2px style G fill:#d6eaf8,stroke:#333,stroke-width:2px

Docker's Client-Server Architecture

Docker uses a client-server architecture with several distinct components that work together.

graph LR A[User] -->|Issues Commands| B[Docker Client] B -->|REST API| C[Docker Daemon] C -->|Manages| D[Containers] C -->|Manages| E[Images] C -->|Manages| F[Networks] C -->|Manages| G[Volumes] style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px style E fill:#fdebd0,stroke:#333,stroke-width:2px style F fill:#d6eaf8,stroke:#333,stroke-width:2px style G fill:#d4efdf,stroke:#333,stroke-width:2px

Key Components

Think of this architecture like a restaurant:

Docker Client

The Docker client is the primary way users interact with Docker. It's a command-line tool that allows you to issue commands to the Docker daemon.

Docker Client Functions

Common Docker Client Commands


# Build an image
docker build -t myapp:1.0 .

# Run a container
docker run -d -p 8080:80 myapp:1.0

# Pull an image from a registry
docker pull nginx:latest

# List running containers
docker ps

# View container logs
docker logs container_id

# Stop a container
docker stop container_id
            

Docker Client Locations

The Docker client can communicate with:


# Connect to a remote Docker daemon
docker -H tcp://remote-docker-host:2375 info

# Use environment variable to set default daemon
export DOCKER_HOST=tcp://remote-docker-host:2375
            

This client flexibility is similar to how you might use a TV remote control (client) to control different TVs (daemons) by simply pointing it at the one you want to interact with.

Docker Daemon (dockerd)

The Docker daemon (dockerd) is the persistent background process that manages Docker objects such as images, containers, networks, and volumes.

graph TB A[Docker Daemon] -->|Manages| B[Container Lifecycle] A -->|Manages| C[Image Management] A -->|Manages| D[Network Management] A -->|Manages| E[Volume Management] A -->|Listens for| F[API Requests] style A fill:#d5f5e3,stroke:#333,stroke-width:2px style B fill:#f9d5e5,stroke:#333,stroke-width:2px style C fill:#f9d5e5,stroke:#333,stroke-width:2px style D fill:#f9d5e5,stroke:#333,stroke-width:2px style E fill:#f9d5e5,stroke:#333,stroke-width:2px style F fill:#f9d5e5,stroke:#333,stroke-width:2px

Docker Daemon Responsibilities

The Docker daemon is like the engine and control systems of a car. You don't directly interact with it, but it's responsible for all the actual work - from processing fuel (images) to turning the wheels (running containers).

The Daemon Runtime Architecture

Docker's architecture has evolved over time. Initially, the Docker daemon directly managed container execution, but now it delegates this to specialized containerd runtime.

graph TD A[Docker Daemon] -->|Uses| B[containerd] B -->|Uses| C[runc] C -->|Creates and Runs| D[Container] style A fill:#d5f5e3,stroke:#333,stroke-width:2px style B fill:#ebdef0,stroke:#333,stroke-width:2px style C fill:#fdebd0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px

containerd and runc

This modular architecture is like how a modern restaurant might have specialized stations: The head chef (Docker daemon) coordinates everything, but delegates specific tasks to the sous chef (containerd), who in turn works with line cooks (runc) to prepare specific dishes (run containers).

Docker REST API

The Docker REST API is the interface used for communication between the Docker client and the Docker daemon. It provides a way to control the daemon programmatically.

API Characteristics

Sample API Endpoints


# List containers
GET /containers/json

# Create a container
POST /containers/create

# Start a container
POST /containers/{id}/start

# List images
GET /images/json

# Create an image (build)
POST /build
            

The REST API is like a common language that allows different tools (Docker CLI, Docker Desktop, Portainer, etc.) to communicate with the Docker daemon using the same vocabulary and grammar.

Using the Docker API Directly

While most users interact with Docker through the client, you can use the API directly for advanced use cases:


# Using curl to list containers via the API
curl --unix-socket /var/run/docker.sock http:/v1.41/containers/json

# Using curl to create a container
curl -X POST --unix-socket /var/run/docker.sock \
  -H "Content-Type: application/json" \
  -d '{"Image":"nginx"}' \
  http:/v1.41/containers/create
            

This direct API access is particularly useful for:

Docker Objects

Docker objects are the entities managed by Docker to run your applications. Understanding these objects is essential for effective Docker usage.

Images

A Docker image is a read-only template with instructions for creating a container. Images:

graph TD A[Image] -->|Layer 1| B[Base OS Layer] A -->|Layer 2| C[Runtime Layer] A -->|Layer 3| D[Dependencies Layer] A -->|Layer 4| E[Application Code Layer] style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px style E fill:#fdebd0,stroke:#333,stroke-width:2px

Images are like blueprints for houses. They contain all the specifications and materials needed, but you don't live in the blueprint - you live in the house built from it.

Containers

A container is a runnable instance of an image. Containers:

To extend our blueprint analogy: if an image is a blueprint, a container is the actual house built from that blueprint, with people living inside and modifications made by the residents.

Networks

Docker networks allow containers to communicate with each other and with the outside world.

graph LR subgraph "Bridge Network" A[Container A] --- B[Bridge] C[Container B] --- B B --- D[Host Network Interface] D --- E[External Network] end style A fill:#f9d5e5,stroke:#333,stroke-width:2px style C fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style D fill:#ebdef0,stroke:#333,stroke-width:2px style E fill:#eaeded,stroke:#333,stroke-width:2px

Docker networks are like the plumbing and electrical systems in a house development. They allow communication between houses (containers) and with the outside world, with different types of connections for different needs.

Volumes

Docker volumes provide persistent storage for container data.

graph TD A[Container] -->|Mounts| B[Volume] C[Host Filesystem] -->|Stores| B D[Another Container] -.->|Can also mount| B style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#f9d5e5,stroke:#333,stroke-width:2px

Volumes are like storage units that can be attached to houses (containers). When you move to a new house, your stored belongings remain intact in the storage unit and can be attached to your new home.

Docker Registry

A Docker registry is a repository for Docker images. It allows you to store and distribute images for use by Docker installations.

Types of Registries

graph LR A[Developer] -->|Push Image| B[Registry] C[Server] -->|Pull Image| B style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px

Working with Registries


# Pull an image from Docker Hub
docker pull nginx:latest

# Tag a local image for a specific registry
docker tag myapp:1.0 username/myapp:1.0

# Push an image to Docker Hub
docker push username/myapp:1.0

# Pull from a private registry
docker pull registry.example.com/myapp:1.0
            

A Docker registry is like a library where blueprints (images) are stored, cataloged, and shared. Anyone with access to the library can check out a copy of a blueprint to build their own structure (container).

Registry Security

Registries typically include security features such as:

Docker Storage

Docker provides several options for storing data, each with different use cases and characteristics.

Storage Drivers

Storage drivers manage the container's writable layer and how images are stored. Common storage drivers include:

Storage drivers control how container layers are stored and accessed on the host system, similar to how different filesystems (NTFS, ext4, etc.) manage files on your computer.

Storage Types

Docker offers different ways to persist data beyond the container lifecycle:

Storage Type Description Use Case
Volumes Docker-managed directories on the host filesystem Persistent data that should be managed by Docker
Bind Mounts Map host directory to container directory When you need to access specific host files
tmpfs Mounts Store data in host memory only Sensitive or temporary data that shouldn't be persisted
graph TB subgraph "Docker Storage Options" A[Container] --- B[Data Storage] B --- C[Volumes] B --- D[Bind Mounts] B --- E[tmpfs Mounts] end style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px style E fill:#fdebd0,stroke:#333,stroke-width:2px

Volume Commands


# Create a named volume
docker volume create mydata

# Run a container with a volume
docker run -v mydata:/data nginx

# List volumes
docker volume ls

# Inspect a volume
docker volume inspect mydata

# Remove a volume
docker volume rm mydata

# Remove all unused volumes
docker volume prune
            

Docker Networking

Docker networking enables communication between containers and with the outside world. Understanding Docker's networking model is essential for building multi-container applications.

Network Drivers

Docker supports several network drivers to accommodate different scenarios:

Driver Description Use Case
bridge Default network driver, creates a private network for containers Standalone containers that need to communicate
host Removes network isolation, container uses host's network When network performance is critical
none Disables networking for a container When a container needs complete isolation
overlay Connects multiple Docker daemons Swarm services across multiple Docker hosts
macvlan Assigns a MAC address to each container When containers need to appear as physical devices

Network Commands


# List networks
docker network ls

# Create a custom bridge network
docker network create mynetwork

# Run a container with a specific network
docker run --network=mynetwork nginx

# Connect a running container to a network
docker network connect mynetwork container_id

# Disconnect a container from a network
docker network disconnect mynetwork container_id

# Inspect a network
docker network inspect mynetwork

# Remove a network
docker network rm mynetwork
            
graph TB subgraph "Host" subgraph "Bridge Network A" A[Container 1] --- B[Container 2] end subgraph "Bridge Network B" C[Container 3] --- D[Container 4] end E[Host Network] --- F[Container 5] end style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#f9d5e5,stroke:#333,stroke-width:2px style C fill:#d5f5e3,stroke:#333,stroke-width:2px style D fill:#d5f5e3,stroke:#333,stroke-width:2px style E fill:#ebdef0,stroke:#333,stroke-width:2px style F fill:#eaeded,stroke:#333,stroke-width:2px

Evolution of Docker Architecture

Docker's architecture has evolved significantly since its inception, becoming more modular and standards-based.

Early Docker (Pre-1.11)

Modern Docker (Post-1.11)

timeline title Evolution of Docker Architecture section Early Days Monolithic Architecture (2013) : Docker daemon directly manages containers section Transition Modularity Begins (2015) : Introduction of libcontainer section Modern Era Modular Architecture (2016-Present) : Docker daemon + containerd + runc OCI Standards (2017-Present) : Standardization of container format and runtime

Benefits of the Evolution

This evolution is like how early cars had integrated systems built by a single manufacturer, but modern cars use standardized components (brakes, transmissions, etc.) from specialized suppliers that adhere to industry standards.

Docker Desktop Architecture

Docker Desktop is a popular tool for developers to run Docker on Windows and macOS. Its architecture differs from Docker on Linux due to the need for virtualization.

Windows Architecture

On Windows, Docker Desktop can use two different backends:

graph TB subgraph "Windows with WSL 2" A[Docker Desktop] -->|Uses| B[WSL 2] B -->|Runs| C[Linux Kernel] C -->|Hosts| D[Docker Engine] D -->|Manages| E[Containers] end style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px style E fill:#fdebd0,stroke:#333,stroke-width:2px

macOS Architecture

On macOS, Docker Desktop uses a lightweight virtual machine:

graph TB subgraph "macOS" A[Docker Desktop] -->|Uses| B[HyperKit VM] B -->|Runs| C[Linux Kernel] C -->|Hosts| D[Docker Engine] D -->|Manages| E[Containers] end style A fill:#f9d5e5,stroke:#333,stroke-width:2px style B fill:#d5f5e3,stroke:#333,stroke-width:2px style C fill:#ebdef0,stroke:#333,stroke-width:2px style D fill:#eaeded,stroke:#333,stroke-width:2px style E fill:#fdebd0,stroke:#333,stroke-width:2px

Docker Desktop's architecture is like running a simulation of a foreign environment (Linux) within your native system (Windows/macOS). This simulation is seamless enough that you can interact with it as if it were native, but it's actually running in a translation layer.

Practical Architecture Considerations

Docker Performance

Understanding Docker's architecture helps optimize performance:

Security Implications

Docker's architecture has security implications to consider:

Orchestration Considerations

When moving beyond single-host Docker:

Hands-On: Exploring Docker Architecture

Let's explore Docker's architecture through commands that reveal its components and behavior.

Examining the Docker Installation


# Check Docker version and architecture details
docker version

# View detailed Docker system information
docker info

# List the Docker client configuration
docker config ls

# Show Docker daemon configuration
cat /etc/docker/daemon.json  # Linux/macOS
notepad %PROGRAMDATA%\\docker\\config\\daemon.json  # Windows
            

Exploring Docker Components


# List running containers
docker ps

# View container details
docker inspect container_id

# Examine container stats
docker stats

# List networks
docker network ls

# View network details
docker network inspect bridge

# List volumes
docker volume ls

# Examine volume details
docker volume inspect volume_name
            

Image and Layer Inspection


# Pull an image to examine
docker pull nginx:latest

# View image details
docker image inspect nginx:latest

# See the image layers
docker history nginx:latest

# View storage usage
docker system df -v
            

Conclusion

Docker's client-server architecture provides a powerful, flexible system for containerizing applications. By understanding the relationships between the Docker client, Docker daemon, and Docker objects, you can better leverage Docker for your development and deployment needs.

Key takeaways from this lecture:

mindmap root((Docker Architecture)) Client-Server Model Docker Client Docker Daemon REST API Components containerd runc OCI Standards Docker Objects Images Containers Networks Volumes Storage Options Storage Drivers Volumes Bind Mounts tmpfs Networking Bridge Host Overlay Macvlan Platforms Linux Native Windows (WSL/Hyper-V) macOS (HyperKit)

In our next lecture, we'll focus on Docker commands and how to use them effectively for managing containers, images, networks, and volumes.

Practice Activities

Activity 1: Explore Docker System Information

  1. Run docker version and identify the client and server components
  2. Run docker info and note the storage driver and network driver being used
  3. Investigate the Docker daemon configuration on your system
  4. Research how to change the default storage driver and what considerations apply

Activity 2: Investigate Container Isolation

  1. Run two containers based on the same image:
    docker run -d --name container1 alpine sleep 1000
    docker run -d --name container2 alpine sleep 1000
  2. Use docker exec to create a file in each container:
    docker exec container1 sh -c "echo 'hello from container1' > /file.txt"
    docker exec container2 sh -c "echo 'hello from container2' > /file.txt"
  3. Verify that the files are different in each container
  4. Investigate the container filesystem layers:
    docker inspect container1 | grep -A 10 GraphDriver
    docker inspect container2 | grep -A 10 GraphDriver
  5. Stop and remove the containers when done

Activity 3: Explore Docker Networks

  1. List the default Docker networks with docker network ls
  2. Create a custom bridge network: docker network create mynetwork
  3. Run containers on different networks and test connectivity:
    docker run -d --name default_container nginx
    docker run -d --name custom_container --network mynetwork nginx
  4. Attempt to ping between containers in different networks
  5. Connect a container to multiple networks:
    docker network connect bridge custom_container
  6. Test connectivity again
  7. Clean up the containers and networks when done

Activity 4: Examine Image Layers

  1. Pull a large image: docker pull node:latest
  2. Examine its layers: docker history node:latest
  3. Create a simple Dockerfile that uses this image as a base
  4. Build your custom image: docker build -t mylayer .
  5. Compare the layers between the base image and your custom image
  6. Modify your Dockerfile to optimize layer caching and rebuild
  7. Compare build times and layer reuse

Challenge: Docker Architecture Diagram

Create a comprehensive diagram of Docker's architecture showing the relationships between:

Include annotations explaining each component's role and how they interact. Use a tool like draw.io, Lucidchart, or even paper and pencil. Present your diagram to the class and explain your understanding of Docker's architecture.

Additional Resources

Official Documentation

Deep Dives

Books

Video Resources