Architecture of Docker

As a seasoned DevOps engineer, I bring a comprehensive set of skills to the table, encompassing version control with Git and GitOps using ArgoCD, containerization with Docker, and orchestration with Kubernetes, Helm, and Istio. I'm proficient in infrastructure provisioning and management using Terraform and Ansible, and have expertise in setting up and managing CI/CD pipelines with Jenkins, Azure Pipelines, and AWS CodePipeline. With extensive experience in cloud platforms, including Azure and AWS, I've deployed and managed applications on Azure Kubernetes Service (AKS) and AWS Elastic Container Service (ECS) and Elastic Container Service for Kubernetes (EKS). Additionally, I've integrated security practices into DevOps pipelines, ensuring secure and compliant software development and deployment. My technical prowess extends to Bash shell scripting, Linux system administration, and programming in Golang. Throughout my journey, I've developed a unique blend of skills that enable me to streamline development, deployment, and management of applications across multiple environments.
Architecture of Docker in a detailed and understandable manner, let's break it down into its key components and their interactions. We'll also explore what happens when you run a docker run command, step by step.
Docker Components
Docker Daemon (dockerd)
The Docker Daemon is the core process that manages Docker containers. It runs as a background process on the host system and listens for Docker API requests.
It is responsible for managing the lifecycle of containers, including creating, running, and stopping them.
The daemon also manages Docker networks, volumes, and images.
Docker CLI (docker)
The Docker CLI is the command-line interface used to interact with the Docker Daemon.
It provides a set of commands (e.g.,
docker run,docker ps,docker stop) that allow users to manage Docker resources.The CLI communicates with the Docker Daemon using the Docker REST API.
Docker REST API
The Docker REST API is a RESTful API that allows clients to interact with the Docker Daemon.
It provides endpoints for managing containers, images, networks, and volumes.
The Docker CLI uses this API to send requests to the Docker Daemon.
containerd
containerd is a daemon that manages the lifecycle of containers.
It is responsible for running and managing containers, including starting, stopping, and deleting them.
containerd is a lower-level component than the Docker Daemon and is used by Docker to manage containers.
runc
runc is a lightweight, portable implementation of the Open Container Initiative (OCI) runtime specification.
It is used by containerd to run containers.
runc provides a low-level interface for running containers and is responsible for creating and managing the container's runtime environment.
containerd-shim
containerd-shim is a process that runs as a child of containerd and is responsible for keeping the container's STDIN, STDOUT, and STDERR streams open.
It acts as a proxy between the container and the Docker Daemon, allowing the Docker Daemon to communicate with the container.
The shim also handles the container's exit and ensures that the Docker Daemon is notified when the container exits.
Docker Run Command Flow
When you run a docker run command, the following components come into play in the following order:
Docker CLI (docker)
The user runs a
docker runcommand, specifying the image and any additional options (e.g.,docker run -it ubuntu /bin/bash).The Docker CLI processes the command and prepares the request to be sent to the Docker Daemon.
Docker Daemon (dockerd)
The Docker CLI sends the request to the Docker Daemon using the Docker REST API.
The Docker Daemon receives the request and processes it.
It checks if the requested image is available locally. If not, it pulls the image from a Docker registry (e.g., Docker Hub).
containerd
The Docker Daemon instructs containerd to create a new container from the specified image.
containerd creates a new container and starts it.
runc
containerd uses runc to create and manage the container's runtime environment.
runc sets up the container's namespace, mounts, and other necessary configurations.
containerd-shim
containerd starts a new containerd-shim process for the container.
The shim process keeps the container's STDIN, STDOUT, and STDERR streams open, allowing the Docker Daemon to communicate with the container.
Detailed Example and Explanation
Let's consider a simple example: running a new Ubuntu container with the command docker run -it ubuntu /bin/bash.
Step 1: Docker CLI (docker)
The user runs the command
docker run -it ubuntu /bin/bash.The Docker CLI processes the command and prepares the request to be sent to the Docker Daemon.
Step 2: Docker Daemon (dockerd)
The Docker CLI sends the request to the Docker Daemon using the Docker REST API.
The Docker Daemon receives the request and processes it.
It checks if the
ubuntuimage is available locally. If not, it pulls the image from Docker Hub.
Step 3: containerd
The Docker Daemon instructs containerd to create a new container from the
ubuntuimage.containerd creates a new container and starts it.
containerd also sets up the necessary configurations, such as the container's namespace and mounts.
Step 4: runc
containerd uses runc to create and manage the container's runtime environment.
runc sets up the container's namespace, mounts, and other necessary configurations.
runc starts the container's process, in this case,
/bin/bash.
Step 5: containerd-shim
containerd starts a new containerd-shim process for the container.
The shim process keeps the container's STDIN, STDOUT, and STDERR streams open, allowing the Docker Daemon to communicate with the container.
The shim also handles the container's exit and ensures that the Docker Daemon is notified when the container exits.
Step 6: Container Running
The container is now running, and the user can interact with it through the Docker CLI.
The user can type commands in the container, and the output will be displayed in the terminal.
Step 7: Container Exit
When the user exits the container (e.g., by typing
exit), the shim process is notified.The shim process ensures that the Docker Daemon is notified of the container's exit.
The Docker Daemon then updates its state to reflect that the container has exited.
Conclusion
In summary, the Docker architecture involves several key components that work together to manage and run containers. The Docker Daemon manages the high-level lifecycle of containers, while containerd and runc handle the lower-level details of running and managing containers. The Docker CLI provides a user-friendly interface for interacting with the Docker Daemon, and the containerd-shim ensures that the Docker Daemon can communicate with running containers. Understanding these components and their interactions is essential for effectively using Docker in development and production environments.



