I Rewrote Docker From Scratch: Here’s What I Learned About Linux Containers + Video

Listen to this Post

Featured Image

Introduction:

Containers have become the backbone of modern cloud-native applications, yet their inner workings often remain a black box to many developers and security professionals. By re-implementing a basic container runtime from scratch, one engineer discovered that Docker is not magic—it is a sophisticated composition of decades-old Linux kernel primitives like namespaces, cgroups, and layered filesystems. Understanding these core components is essential for effective container security, threat modeling, and infrastructure hardening.

Learning Objectives:

  • Understand the Linux kernel features (namespaces, cgroups, overlayfs) that enable containerization.
  • Learn how to manually configure and interact with these primitives using command-line tools.
  • Gain insight into container networking fundamentals using virtual Ethernet pairs and bridges.
  • Identify security boundaries and potential misconfigurations in container runtimes.
  • Apply hands-on commands to inspect, limit, and debug containerized environments.

You Should Know:

1. Linux Namespaces: The Foundation of Isolation

At the heart of every container are Linux namespaces, which isolate global system resources so that processes inside the container see their own view of the system. When you run a container, the runtime creates new namespaces for the process.

Step‑by‑step guide explaining what this does and how to use it:
To see this in action without Docker, you can manually launch a process in a new namespace using the `unshare` command.

 Run a bash shell in a new mount, PID, and network namespace
sudo unshare --mount --pid --net --fork bash

Inside the new namespace, check the processes
ps aux
 You will notice only a few processes, as the PID namespace is isolated.

Check the network interfaces
ip link
 You will see only a loopback interface (lo), isolated from the host.

To see all namespaces on your system and which processes belong to them:

lsns
 This lists all current namespaces and their types (net, mnt, pid, etc.)

You can also enter an existing container’s namespace from the host for debugging:

 Find the PID of a container process (e.g., from <code>docker inspect</code>)
 Then enter its network namespace
nsenter -t <PID> -n ip addr

This shows that a container is simply a group of processes running within a specific set of namespaces. From a security perspective, misconfigured namespace sharing (e.g., sharing the host’s PID or network namespace) can severely weaken isolation.

2. Control Groups (cgroups v2): Enforcing Resource Limits

Namespaces provide isolation, but they do not limit resource usage. That is the job of cgroups. Cgroups allow you to restrict CPU, memory, and I/O for a group of processes.

Step‑by‑step guide explaining what this does and how to use it:
On a system with cgroups v2 (check with mount | grep cgroup), you can create a child cgroup and set limits.

 Create a new cgroup for a demo container
sudo mkdir /sys/fs/cgroup/container-demo

Check the default settings
cat /sys/fs/cgroup/container-demo/cpu.max
cat /sys/fs/cgroup/container-demo/memory.max

Set a memory limit of 256MB (256  1024  1024 = 268435456 bytes)
echo 268435456 | sudo tee /sys/fs/cgroup/container-demo/memory.max

Set a CPU limit (e.g., 50% of one core: 50000 out of 100000)
echo "50000 100000" | sudo tee /sys/fs/cgroup/container-demo/cpu.max

Now, run a process and add its PID to the cgroup.procs file
sudo bash -c "echo $$ >> /sys/fs/cgroup/container-demo/cgroup.procs"
 Any child processes will also be subject to these limits.

You can then run a stress test (e.g., stress --vm-bytes 300M --vm-keep -m 1) to see the kernel enforce the limit. In production, misconfigured or missing cgroup limits can lead to resource exhaustion attacks (DoS) from a compromised container.

3. OverlayFS: Writable Container Layers

Docker images are built from read-only layers. When you run a container, OverlayFS merges these layers and adds a thin writable layer on top. This is why changes inside a container do not affect the base image.

Step‑by‑step guide explaining what this does and how to use it:
You can manually create an overlay mount to understand the mechanism.

 Create directories for the lower (base), upper (changes), work, and merged layers
mkdir -p ~/overlay-demo/{lower,upper,work,merged}

Populate the lower layer with a sample file
echo "Hello from base image" > ~/overlay-demo/lower/base.txt

Mount the overlay
sudo mount -t overlay overlay -o lowerdir=~/overlay-demo/lower,upperdir=~/overlay-demo/upper,workdir=~/overlay-demo/work ~/overlay-demo/merged

Check the merged view
cat ~/overlay-demo/merged/base.txt

Create a new file in the merged directory
echo "New file from container" > ~/overlay-demo/merged/new.txt

Check the upper layer - the changes are stored here
ls ~/overlay-demo/upper/
 The lower layer (base image) remains untouched.

When a file is deleted from the merged view, a “whiteout” file is created in the upper layer to hide it. Understanding this helps in forensic analysis of compromised containers and in designing secure image build processes.

4. Bridge Networking: Connecting Containers

Containers on the same host communicate via a virtual network bridge. This is implemented using a Linux bridge and virtual Ethernet (veth) pairs.

Step‑by‑step guide explaining what this does and how to use it:
Here’s how to manually create a bridge and connect a network namespace to it.

 Create a bridge
sudo ip link add name br0 type bridge
sudo ip link set br0 up
sudo ip addr add 172.18.0.1/24 dev br0

Create a network namespace (simulating a container)
sudo ip netns add container1

Create a veth pair
sudo ip link add veth0 type veth peer name veth1

Attach one end (veth1) to the bridge
sudo ip link set veth1 master br0
sudo ip link set veth1 up

Move the other end (veth0) into the container's namespace
sudo ip link set veth0 netns container1

Inside the container namespace, configure the interface
sudo ip netns exec container1 ip link set lo up
sudo ip netns exec container1 ip link set veth0 up
sudo ip netns exec container1 ip addr add 172.18.0.10/24 dev veth0
sudo ip netns exec container1 ip route add default via 172.18.0.1

From the host, you can now ping the container
ping -c 2 172.18.0.10

This demonstrates that container networking is simply standard Linux bridging. Security implications include the potential for ARP spoofing or MAC flooding on the bridge if not properly secured (e.g., using `ebtables` or `iptables` to restrict traffic).

5. Interactive Mode and Pseudo-Terminals (PTY)

The `-it` flag in Docker does more than just keep STDIN open. It allocates a pseudo-terminal (PTY) for the container, which is necessary for interactive applications like a shell to handle signals and job control correctly.

Step‑by‑step guide explaining what this does and how to use it:
You can replicate this behavior using `socat` or by manually creating a PTY.

 Create a new PTY and attach a shell to it
sudo socat PTY,link=/tmp/docker-pty,raw,echo=0 EXEC:/bin/bash

In another terminal, connect to that PTY
sudo screen /tmp/docker-pty

Inside a running container, you can inspect the PTY device:

 Find a container's PID and list its open file descriptors
docker inspect --format '{{.State.Pid}}' <container-id>
sudo ls -l /proc/<PID>/fd/
 You will see a symlink to /dev/pts/ for the TTY.

From a security standpoint, if a container is run with a TTY allocated and is compromised, an attacker might have a more stable interactive shell, but the main risk lies in escape vulnerabilities that leverage TTY driver bugs.

6. Putting It All Together: The Container Runtime

The original post’s project, Xocker, combines all these primitives: unshare for namespaces, cgroupfs for limits, pivot_root for filesystem isolation, and veth pairs for networking.

Step‑by‑step guide explaining what this does and how to use it:

To clone and test a similar minimal runtime:

git clone https://github.com/truongnhatanh7/xocker.git
cd xocker
make
sudo ./xocker run -it --memory 256 --cpus 0.5 alpine sh

This command will:

  • Create new namespaces (using `unshare` or `clone` with flags).
  • Set up cgroups for the process.
  • Prepare the root filesystem using OverlayFS.
  • Configure networking in the container’s namespace.
  • Execute the shell with a PTY.

Examining the code (written in Go) reveals how each syscall is invoked, providing a clear map of the attack surface for container escapes and privilege escalation.

What Undercode Say:

  • The perceived complexity of Docker is an illusion; it is a masterful orchestration of fundamental Linux components. For defenders and attackers alike, this means that vulnerabilities in containers are often vulnerabilities in the Linux kernel itself, misapplied.
  • Security in containerized environments hinges on correctly configuring these underlying primitives. A simple misstep, such as running a container with `–privileged` or sharing the host’s namespaces, dismantles the isolation that namespaces and cgroups provide, directly exposing the host.

Key Takeaway 1: Master the primitives to master the platform. You cannot secure what you do not understand. Knowing how to manually create namespaces, set cgroup limits, and build bridges demystifies the stack and reveals the true boundaries of trust.

Key Takeaway 2: The container runtime is a security-critical component. Any bug in the runtime’s handling of these syscalls (like the CVE-2022-0492 cgroup escape) can lead to host compromise. Therefore, keeping the container runtime (runc, containerd) updated is as important as patching the kernel.

Prediction:

As infrastructure continues to evolve, we will see a shift towards “microVMs” (like Firecracker) and “confidential containers” that add a hardware-enforced isolation layer beyond traditional namespaces. This is a direct response to the realization that while Linux namespaces are powerful, the shared kernel model remains a single point of failure for multi-tenant environments. The future of container security lies in minimizing the kernel’s attack surface and moving isolation left, back to the hardware.

▶️ Related Video (84% Match):

🎯Let’s Practice For Free:

IT/Security Reporter URL:

Reported By: Anh Truong – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky