I Thought I Understood Containers. Then I Tried Building One.
The author, despite passing a Docker exam, realized practical container knowledge differed from theoretical understanding. Initial attempts with the unshare command revealed misunderstandings of PID namespaces, requiring the --fork flag to correctly establish PID 1 within the new namespace. Subsequently, remounting the /proc filesystem within the namespace was crucial for tools like ps to reflect the isolated process hierarchy accurately. The UTS namespace demonstration showed how hostnames could be isolated, proving the concept with a clear control and treatment scenario.The journey continued with pivot_root, where the author aimed to grant a process its own filesystem. An initial hurdle involved a dynamically linked BusyBox executable failing because its required interpreter was unavailable in the new root filesystem. The solution involved using a statically linked BusyBox as a bridge during the filesystem transition and addressing Bash's hash cache that remembered old command paths. A Mac-specific issue with virtiofs and symlink execution was resolved by moving the root filesystem to a native container path.The pivot_root operation itself required specific setup: the new root had to be a mount point, with the old root prepared separately before the actual change. Successfully executing commands within the newly assembled filesystem, like displaying /etc/os-release from Alpine Linux, provided a tangible reward. Finally, exploring cgroups as a filesystem API demonstrated resource limitation, revealing the "no internal processes" rule for enabling controllers in cgroup v2.By carefully evacuating processes and then enabling controllers on parent cgroups, the author successfully set memory and PID limits for a child cgroup. Enforcing these limits, particularly observing an Out-Of-Memory (OOM) kill event via dmesg, solidified the understanding of cgroups not as abstract settings but as direct kernel filesystem interactions. This hands-on experience demystified Kubernetes Pods, revealing them as organized implementations of these fundamental Linux primitives: namespaces, filesystem isolation, and cgroups. Consequently, containerization tools like Docker, containerd, and Kubernetes transformed from branded products into structured arrangements of these core scripts.
unsharecommand revealed misunderstandings of PID namespaces, requiring the--forkflag to correctly establish PID 1 within the new namespace. Subsequently, remounting the/procfilesystem within the namespace was crucial for tools likepsto reflect the isolated process hierarchy accurately. The UTS namespace demonstration showed how hostnames could be isolated, proving the concept with a clear control and treatment scenario.The journey continued withpivot_root, where the author aimed to grant a process its own filesystem. An initial hurdle involved a dynamically linked BusyBox executable failing because its required interpreter was unavailable in the new root filesystem. The solution involved using a statically linked BusyBox as a bridge during the filesystem transition and addressing Bash's hash cache that remembered old command paths. A Mac-specific issue withvirtiofsand symlink execution was resolved by moving the root filesystem to a native container path.Thepivot_rootoperation itself required specific setup: the new root had to be a mount point, with the old root prepared separately before the actual change. Successfully executing commands within the newly assembled filesystem, like displaying/etc/os-releasefrom Alpine Linux, provided a tangible reward. Finally, exploring cgroups as a filesystem API demonstrated resource limitation, revealing the "no internal processes" rule for enabling controllers in cgroup v2.By carefully evacuating processes and then enabling controllers on parent cgroups, the author successfully set memory and PID limits for a child cgroup. Enforcing these limits, particularly observing an Out-Of-Memory (OOM) kill event viadmesg, solidified the understanding of cgroups not as abstract settings but as direct kernel filesystem interactions. This hands-on experience demystified Kubernetes Pods, revealing them as organized implementations of these fundamental Linux primitives: namespaces, filesystem isolation, and cgroups. Consequently, containerization tools like Docker, containerd, and Kubernetes transformed from branded products into structured arrangements of these core scripts.