DevOps & Cloud · Pro

Container Runtime From Scratch

A Docker-like runtime in Go that isolates processes with Linux namespaces and cgroups, pulls OCI images, and runs them with an overlay rootfs

Pro20-40 hoursGoC

You build a minimal container runtime in Go that clones a child process into new Linux namespaces, applies cgroup v2 resource limits, mounts an overlayfs rootfs assembled from OCI image layers, and execs a user command inside the isolated environment. The project exposes the exact kernel primitives that Docker and containerd sit on top of, which makes debugging production container issues far more tractable. Unlike toy demos, this version actually pulls a real image from a registry, unpacks it, and pivots the root, giving you a working artifact you can demo.

What you build

  • Pulls OCI images from a public registry (Docker Hub) using the distribution spec and unpacks layer tarballs
  • Creates isolated PID, mount, UTS, IPC, and network namespaces via clone(2) flags
  • Assembles an overlayfs rootfs from the image layers so the container gets a writable scratch layer
  • Pivots the root filesystem with pivot_root and bind-mounts /proc, /sys, and /dev
  • Enforces CPU and memory limits through the cgroup v2 unified hierarchy
  • Runs an arbitrary command inside the container and streams stdout/stderr back to the host terminal
  • Cleans up cgroup directories and unmounts all overlay mounts on exit

What it teaches

  • How Linux namespaces (PID, mount, UTS, network) isolate processes at the kernel level
  • The OCI image and distribution specifications: manifests, layer blobs, and content-addressable storage
  • How overlayfs composes read-only layers with a writable upperdir to give containers a copy-on-write filesystem
  • How cgroup v2 enforces resource constraints and the unified hierarchy layout under /sys/fs/cgroup
  • The pivot_root system call and why it is preferred over chroot for rootfs switching in container runtimes
  • Safe Go patterns for executing privileged system calls and handling namespace-crossing re-exec tricks

How it works

  1. 1

    Pull image

    • Fetch OCI manifest from registry
    • Download layer blobs by digest
    • Unpack tarballs to layer cache
  2. 2

    Build rootfs

    • Stack layers as overlayfs lowerdir chain
    • Create writable upperdir + workdir
    • Mount overlay at a merged path
  3. 3

    Fork child

    • Clone with PID/mount/UTS/net namespace flags
    • Register child PID in cgroup v2 subtree
    • Apply memory.max and cpu.max
  4. 4

    Pivot root

    • Call pivot_root into merged overlay
    • Bind-mount /proc, /sys, /dev
    • Exec user command as PID 1
  5. 5

    Cleanup

    • Unmount overlay and bind mounts
    • Remove cgroup subtree directory
    • Delete scratch upperdir
fig. 01 — how the runtime assembles and launches a container

Sign in to open the build guide

Free account. Get the step-by-step build and every resource link.

Sign in to continue

Take it further

  • Implement a basic network namespace with a veth pair, a bridge on the host, and NAT via iptables so the container gets outbound internet access
  • Add a simple image layer cache with content-addressable storage keyed by digest so repeated runs do not re-download layers
  • Support a minimal Dockerfile-like spec file that lets you define environment variables, a working directory, and an entrypoint without wrapping Docker

More like this

All projects