projects / 03
gobox
daemonless container runtime
A daemonless container runtime built from Linux kernel primitives. gobox run sh re-executes itself into new PID, UTS and mount namespaces, stacks a throwaway writable layer over a read-only Alpine rootfs with OverlayFS, pivots into it and mounts a fresh /proc, so the shell wakes up as PID 1 on its own hostname.
how it works
- 01
Fork into namespaces
gobox run re-executes itself through /proc/self/exe with new PID, UTS and mount namespaces, so the child sees its own process tree, hostname and mounts.
- 02
Limit
The parent writes pids.max 20 and memory.max 500M into a cgroup v2 directory and moves the child into it.
- 03
Build the root
The child mounts OverlayFS: a read-only Alpine rootfs underneath, a fresh writable layer on top.
- 04
Pivot
It bind-mounts the merged directory, calls pivot_root into it, then unmounts and removes the old root so no host path stays reachable. A fresh /proc is mounted.
- 05
Run and clean up
The command runs as PID 1 with hostname gobox-container. When it exits, the parent deletes the writable layer, so every run starts clean.
design decisions
pivot_root over chroot
chroot only changes the apparent root and can be escaped by a privileged process. pivot_root swaps the mount namespace's root, and detaching the old one leaves nothing to climb back to.
Raw cgroup files over a library
Writing values straight into /sys/fs/cgroup is what docker run --memory does underneath, and it keeps every step visible in the source.
OverlayFS for the filesystem
The base image is never copied or modified. Writes land in a throwaway upper layer, which makes startup instant and teardown a single delete.
highlights
- pivot_root rather than chroot, then the host's old root is unmounted and detached
- The writable upperdir is discarded on exit; the Alpine base image is never modified
- pids.max 20 and memory.max 500M written straight to /sys/fs/cgroup, so a fork bomb hits a wall
known limitations
- Needs Linux (or WSL2) and root.
- No network, IPC or user namespace: the container shares the host's network stack.
- Limits processes and memory only; there is no CPU limit.
- Fixed cgroup and overlay paths, so one container runs at a time.
stack
- go
- linux
- namespaces
- cgroups v2
- overlayfs