Docker is weird
Docker is an interesting and somewhat complex container technology. The author began creating their own container runtime out of curiosity, but quickly discovered that Docker has some peculiar characteristics. Unlike virtual machines, containers are simply processes with specific restrictions imposed upon them. The host's kernel remains operational, and these processes can even be observed within the `/proc` directory.
The author notes that Docker isn't a single feature of the Linux kernel; instead, it relies on five distinct kernel features working together. Namespaces limit what the host and container can see, while cgroups control resource usage for each container. Additionally, there exists a complex network configuration that isolates containers' networks.
Docker images are essentially folders stored by Docker and then chrooted (or pivot_rooted) to make that folder the root directory for the container's process. For instance, running `docker run -it --rm ubuntu /bin/bash` instructs Docker to create a container using the `ubuntu` image and execute the `bash` command inside that container. The container runtime, runc, is written in Go, a programming language known for its concurrency features.
However, Go's runtime can present challenges for a container runtime. Go's native multi-threaded design can complicate certain operations, as many Linux system calls require a single-threaded environment. To overcome this, runc uses a separate C module that executes before Go's runtime initializes, allowing it to handle the necessary system calls.
The author also points out that Go does not have a fork function, which could be an issue for a container runtime. Forking is a crucial operation for creating a new process and setting up restrictions. To compensate, runc uses a technique involving `/proc/self/exe` and special command-line arguments to mimic the fork operation.
Moreover, many Linux kernel APIs used by container runtimes require root privileges. This means that the Docker daemon typically runs as root, which can present security challenges. However, the author suggests that the situation has improved over time, with rootless container runtimes becoming more prevalent.
Finally, the author mentions that networking is one area where rootless container runtimes may struggle. In such environments, they must reimplement the entire networking stack in userspace to provide the same features as Docker, which can be a challenging task. Despite the complexities, the author finds the process of creating their own container runtime to be an enlightening experience, gaining valuable insights into Docker's inner workings.
Written by urgent.news from Lobsters's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.