Understanding Container Technology
Containers are a type of sandbox technology. As the name suggests, a sandbox is a technology that can "package" applications like a container, ensuring that applications do not interfere with each other due to established boundaries. Moreover, applications contained within these "containers" can be migrated and run across different system environments.Before diving into the principles behind container technology, it's essential to understand the concept of processes. A process's static representation is a program, typically resting quietly on a disk. Once running, it transforms into the sum of data and states within the computer—its dynamic representation. The core functionality of container technology involves creating a "boundary" for processes by constraining and modifying their dynamic behaviors.
Docker Container Technology
For most Linux containers, including Docker, Cgroups technology is primarily used to impose constraints, while Namespace technology is the primary method for modifying the process view.Imagine you have a Docker project running on a Linux operating system, say Ubuntu 22.04. Let's create a container to experiment:
$ docker run -it busybox /bin/sh
This Docker command initiates a container based on the busybox image and runs an interactive shell session within it.
docker run
: Creates and starts a new container instance.
-i
: Keeps STDIN open even without an attached terminal, allowing interaction with the container.
-t
: Assigns a pseudo-terminal or terminal, creating an interactive shell environment.
/bin/sh
: Specifies the command to run upon container startup, which in this case, launches a shell session within the container.
Processes Inside the Container
Thus, the Ubuntu machine becomes a host, and a container running /bin/sh operates within it. This example and its underlying principle should be familiar to seasoned Docker users. If you execute the ps command inside the container, you'll notice something intriguing:
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
10 root 0:00 ps
Here, the initial /bin/sh executed within Docker is process number 1 (PID=1) inside the container, with only two processes running. This implies that the /bin/sh and the ps command we just executed have been isolated within a distinct environment from the host.
The Namespace Mechanism
How is this achieved?Typically, when a /bin/sh program runs on the host, the operating system assigns it a process ID, such as PID=100, which uniquely identifies it. When running this program within a Docker container, Docker applies an "illusion" so that the process, which is actually PID=100, believes it is the first process (PID=1). This mechanism manipulates the process space of isolated applications, allowing them to see recalculated process IDs.
Linux's Namespace Technology
The use of Namespaces is quite interesting: it's merely an optional parameter for creating new processes in Linux. The system call for creating processes in Linux is clone(), as follows:
int pid = clone(main_function, stack_size, SIGCHLD, NULL);
This call creates a new process and returns its process ID, pid. When using the clone()
system call to create a new process, one can specify the CLONE_NEWPID argument:
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
The newly created process will then "see" a fresh process space where its PID is 1. This "illusion" doesn't change the actual PID in the host's process space, which remains the real value, such as 100.
Multiple Namespaces in Action
Repeated execution of the above clone()
call would create multiple PID Namespaces. Each Namespace's application processes believe they are the first process within their respective containers, unaware of the host's actual process space or the specifics of other PID Namespaces. Besides PID Namespace, Linux offers Mount, UTS, IPC, Network, and User Namespaces to "obscure" various process contexts.Mount Namespace
- Mount Namespace: It allows isolated processes to see only the mount points relevant to the current Namespace, meaning processes within the container are oblivious to other mount points on the host.
Network Namespace
Network Namespace: It provides isolated processes with a view of the network devices and configurations specific to the current Namespace. Each Network Namespace has its own network devices, IP addresses, routing tables, and port numbers, separate from the host and other Namespaces.
Other Namespaces
- UTS Namespace: It isolates node name (hostname) and network hostname information.
- IPC Namespace: It segregates resources for inter-process communication, such as message queues and semaphores.
- User Namespace: It isolates user and group IDs, enabling mapping of containerized user IDs to different IDs on the host for enhanced security.
The Implementation Principle of Docker
Containers
This is the fundamental implementation principle of Linux containers. Thus, the seemingly complex concept of Docker containers essentially involves specifying a set of Namespace parameters when creating a container process. Consequently, the container can only "see" the resources, files, devices, states, or configurations limited by the current Namespace, remaining completely oblivious to the host and unrelated programs.
Comparing Containers to Virtual Machines
Containers, therefore, are a special kind of process. When considering the idea of allocating an independent space for processes, virtual machines come to mind. They simulate hardware through Hypervisor software, running a complete guest operating system to achieve application isolation. In contrast, Docker containers achieve isolation through Namespace and Cgroups technology while sharing the host's operating system kernel.
Docker's Lightweight Virtualization
Docker is often referred to as a "lightweight" virtualization technology because it directly leverages host resources without the need for hardware simulation or running an additional operating system. This results in significant advantages over traditional virtual machines in terms of startup speed, resource utilization, and performance.
Conclusion
Docker container technology provides an isolated yet lightweight environment for application processes through Namespace and Cgroups technology. This technology enables containers to start quickly, run efficiently, and maintain isolation from the host and other containers, making it an indispensable technology in modern cloud computing and microservices architectures.