A software developer who decided to build a custom container runtime has documented surprising findings about how Docker actually works, revealing that the technology relies on several loose components rather than a unified system.

According to the developer’s analysis, containers are not a distinct Linux kernel feature. Instead, they are regular processes running on the host kernel with special restrictions applied through five separate Linux kernel features working in combination. Namespaces handle visibility—hiding what the host and container can see from each other. Cgroups limit how many resources a container can use. Additional networking features provide network isolation between containers, though the developer notes these networking mechanisms are complex and not fully understood through their research.
The developer also found that Docker images are surprisingly simple: they are just folders stored by Docker that become a container’s root directory through the chroot or pivot_root system call. When running docker run -it --rm ubuntu /bin/bash, Docker downloads the Ubuntu image, stores it, and executes the shell from that directory.
The source code reveals unexpected design challenges. Docker’s container runtime, runc, is written in Go—a language the developer characterizes as poorly suited for this purpose. Go’s runtime is inherently multi-threaded, but many Linux system calls required for container management must run in a single-threaded environment. To work around this, runc uses a C module that executes before Go’s runtime initializes to handle these critical system calls.
Go’s lack of a fork function creates another workaround. A container runtime typically needs to fork a process, apply restrictions, then execute the desired program. Since Go’s fork only affects the main thread, runc instead calls /proc/self/exe with special command-line arguments to approximate forking behavior.
Docker also requires root privileges to function. Many Linux kernel APIs used by container runtimes need root access, so the Docker daemon typically runs as root. The developer notes that rootless container runtimes exist but must reimplement the entire networking stack in user space to provide equivalent functionality.
The developer concludes that building a custom implementation of a tool already in use is an effective learning method.
Key facts
- Containers are processes with restrictions, not a distinct Linux kernel feature
- Containers combine five separate Linux kernel features: namespaces, cgroups, and networking isolation
- Docker images are folders that become a container’s root directory via chroot or pivot_root
- Docker’s runc runtime is written in Go, which creates challenges for single-threaded system calls
- Docker daemon typically runs as root to access required Linux kernel APIs
