A minimal container runtime written in Go, built to explore how Linux
containers actually work under the hood. It isolates a process using Linux
namespaces, builds a throwaway root filesystem by copying only the binaries you
ask for (plus their shared-library dependencies), and chroots into it before
executing your command.
This is an educational project, not a production runtime. It is a good way to
see unshare(2), chroot(2), and dynamic-linker resolution work together
without the abstraction of Docker or runc.
Running a command goes through four steps (container/cmd/main.go):
- Namespace isolation (
namespace.go) — the process callsunsharewith new mount, UTS, IPC, and network namespaces (CLONE_NEWNS,CLONE_NEWUTS,CLONE_NEWIPC,CLONE_NEWNET). - Sandbox construction (
setup.go) — each entry inreq.binariesis copied intocontainer/sandbox/. For every binary, its shared libraries are resolved withlddand copied intolib/andlib64/so it can run in isolation. - Filesystem isolation (
chroot.go) — the processchroots intocontainer/sandbox/and changes its working directory to/. - Execution — the requested command is run inside the sandbox with stdio wired to the host terminal.
- Linux (uses
unshareandchrootsyscalls) - Go 1.23+
- Root privileges (namespace creation and
chrootrequire them)
Edit req.binaries (one path per line). You can list individual executables or
whole directories:
../../iso/toRun
/bin/ls
/bin/pwd
/bin/tree
Listing /bin and /usr/bin has the same effect — every executable in the
directory is copied in.
From container/cmd/:
sudo go run . ./pwd
sudo go run . ./ls
sudo go run . ./tree /some/dirOr build a binary and run that:
sudo go build -o cmd .
sudo ./cmd ./ls| Path | Purpose |
|---|---|
container/cmd/ |
The runtime: namespace setup, sandbox build, chroot, exec. |
container/sandbox/ |
Generated root filesystem (populated at runtime). |
iso/toRun.go |
A probe program that demonstrates remaining isolation gaps. |
req.binaries |
List of binaries/directories to include in the sandbox. |
- No PID or user namespace, so host processes remain visible via
/procand UIDs are not remapped (seeiso/toRun.go). - No cgroup resource limits.
- The sandbox is not cleaned up between runs.
- Flattens all copied binaries into the sandbox root rather than preserving their original paths.
No license has been specified yet.