NJVERSE // BOOT
>NJVERSE OS v3.14 — BOOT SEQUENCE INITIATED
>loading kernel modules...
>mounting /sys/identity... OK
>applying user preferences...
>spawning interface threads...
>connecting BKK :: 13.7563°N, 100.5018°E
>SYSTEM READY
~/ / posts / 0x02
POST 0x02//systems2026.03.30 // 18 min read

building a 600-line container runtime in Go (because why not)

cgroups, namespaces, and a healthy disrespect for runc. not production. probably illegal in 14 states.

NJ
Nattapong Jaisabai
Software Engineer · published 2026.03.30

containers are not magic. containers are a small pile of linux primitives wearing a trench coat. you can build one in an afternoon if you don't care about correctness, security, performance, or your friendships.

i didn't care about any of those things, so i built one.

the four ingredients

  • namespaces — for isolation (pid, mount, net, uts, ipc, user)
  • cgroups v2 — for resource limits (cpu, mem, io)
  • an overlay filesystem — for the rootfs
  • vibes — for everything else

the entire fork-and-exec

cmd := exec.Command("/proc/self/exe", append([]string{"child"}, args...)...)
cmd.SysProcAttr = &syscall.SysProcAttr{
    Cloneflags: syscall.CLONE_NEWUTS |
                syscall.CLONE_NEWPID |
                syscall.CLONE_NEWNS  |
                syscall.CLONE_NEWNET |
                syscall.CLONE_NEWIPC |
                syscall.CLONE_NEWUSER,
}
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
must(cmd.Run())

in the child you mount /proc inside the new pid namespace, pivot_root onto your overlay, set the hostname to something embarrassing (mine is 'localhorst'), and exec the user's command. that's it. that is the whole thing. you have invented a sad runc.

do not use this in production. do not use this in staging. do not let it within ten meters of an audit. i love you.

what's actually hard

cgroups v2 was a delight after years of fighting v1's hierarchies. user namespaces remain a special kind of nightmare — uid mappings, capability semantics, the small but persistent voice in the back of your head whispering 'are you sure'. networking, of course, is its own continent. veth pairs and a bridge get you basically nowhere; routes, iptables, dns, all of it has to be built. give up early and shell out to slirp4netns. don't be a hero.

EOF · 0x02 · last edit 2026.03.30// thanks for reading.
← PREVIOUS
the cache invalidation post you didn't ask for
2026.02.11 · //perf · 9 min
NEXT →
i RCE'd my own webapp and it was, frankly, embarrassing
2026.04.22 · //sec · 11 min
← back to all posts