Project 3: “Container Runtime from Scratch” — Containers / Linux Internals

A minimal container runtime in C or Go that uses Linux namespaces, cgroups, and chroot to isolate processes—like a simplified runc.

Quick Reference

Attribute Value
Primary Language See main guide
Alternative Languages N/A
Difficulty Intermediate-Advanced
Time Estimate 1-2 weeks
Knowledge Area See main guide
Tooling See main guide
Prerequisites C or Go, Linux systems programming basics, understanding of processes

What You Will Build

A minimal container runtime in C or Go that uses Linux namespaces, cgroups, and chroot to isolate processes—like a simplified runc.

Why It Matters

This project builds core skills that appear repeatedly in real-world systems and tooling.

Core Challenges

  • Using namespaces (PID, NET, MNT, UTS, IPC, USER) to isolate the container (maps to: OS-level isolation)
  • Implementing cgroups to limit CPU/memory (maps to: resource management)
  • Setting up a root filesystem with pivot_root (maps to: filesystem isolation)
  • Creating virtual network interfaces (maps to: container networking)

Key Concepts

  • Concept Resource
  • |———|———-|
  • Linux namespaces “The Linux Programming Interface” Ch. 28 - Michael Kerrisk
  • cgroups “How Linux Works, 3rd Edition” Ch. 8 - Brian Ward
  • Container security “Container Security” Ch. 1-5 - Liz Rice
  • Filesystem isolation “Linux System Programming” Ch. 2 - Robert Love

Real-World Outcome

$ ./mycontainer run alpine /bin/sh

[MyContainer] Creating container 'alpine-c4a2f1'
[MyContainer] Setting up namespaces...
  ✓ PID namespace (isolated process tree)
  ✓ Mount namespace (isolated filesystem)
  ✓ Network namespace (isolated network stack)
  ✓ UTS namespace (isolated hostname)
  ✓ IPC namespace (isolated IPC resources)
[MyContainer] Setting up root filesystem...
  → Extracting alpine rootfs to /var/lib/mycontainer/alpine-c4a2f1/rootfs
  → Mounting proc, sys, dev
  → Pivot root to container rootfs
[MyContainer] Configuring cgroups...
  → Memory limit: 512 MB
  → CPU limit: 50% of 1 core
  → Creating cgroup: /sys/fs/cgroup/mycontainer/alpine-c4a2f1
[MyContainer] Setting up networking...
  → Creating veth pair: veth0-c4a2f1 <-> veth1-c4a2f1
  → Moving veth1-c4a2f1 into container namespace
  → Assigning IP: 172.16.0.2/24
  → Setting up NAT on host
[MyContainer] Container ready! (boot time: 1.2s)

/ # ps aux
PID   USER     COMMAND
    1 root     /bin/sh          ← We're PID 1! This is a container!
    5 root     ps aux

/ # cat /proc/1/cgroup
12:memory:/mycontainer/alpine-c4a2f1      ← We're in a cgroup
11:cpu:/mycontainer/alpine-c4a2f1

/ # hostname
alpine-c4a2f1                              ← Custom hostname (UTS namespace)

/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536
    inet 127.0.0.1/8 scope host lo
3: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
    inet 172.16.0.2/24 scope global eth0  ← Container has its own IP

/ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=117 time=12.3 ms  ← Internet works!

/ # dd if=/dev/zero of=/tmp/test bs=1M count=600
dd: writing '/tmp/test': No space left on device  ← Memory limit enforced!
524+0 records in
523+0 records out

/ # exit

[MyContainer] Cleaning up container 'alpine-c4a2f1'...
  → Removing veth pair
  → Deleting cgroup
  → Unmounting filesystems
  → Removing rootfs
[MyContainer] Container stopped (uptime: 2m 14s)

$ ./mycontainer stats

CONTAINER     CPU    MEM USAGE / LIMIT     NET I/O       PIDS
alpine-c4a2f1 12.4%  145MB / 512MB        1.2KB / 850B  3

Implementation Guide

  1. Reproduce the simplest happy-path scenario.
  2. Build the smallest working version of the core feature.
  3. Add input validation and error handling.
  4. Add instrumentation/logging to confirm behavior.
  5. Refactor into clean modules with tests.

Milestones

  • Milestone 1: Minimal working program that runs end-to-end.
  • Milestone 2: Correct outputs for typical inputs.
  • Milestone 3: Robust handling of edge cases.
  • Milestone 4: Clean structure and documented usage.

Validation Checklist

  • Output matches the real-world outcome example
  • Handles invalid inputs safely
  • Provides clear errors and exit codes
  • Repeatable results across runs

References

  • Main guide: VIRTUALIZATION_HYPERVISORS_HYPERCONVERGENCE.md
  • Primary references are listed in the main guide