Sigil is a low-level container runtime written in Rust. It implements process supervision, Linux namespaces, filesystem isolation, and cgroups from scratch to demonstrate how containers actually work under the hood.
The goal of this project is to understand and build the core primitives behind tools like Docker and runc rather than treating them as black boxes.
- Process supervision with proper signal forwarding
- PID namespace with init process (PID 1) handling
- UTS namespace for hostname isolation
- Mount namespace with private propagation
- Root filesystem isolation using pivot_root
- Proc filesystem mounted inside container
- Basic cgroups v2 support for memory limits
- Clean separation between runtime and isolation layers
Sigil is structured into clearly separated components:
src/
runtime/
supervisor.rs # process lifecycle, signals, waitpid
child.rs # child bootstrap and init (PID 1)
signals.rs # signal handling
isolation/
namespaces.rs # namespace setup
mounts.rs # mount propagation
fs.rs # rootfs and pivot_root
cgroups.rs # cgroup v2 management
config/ # CLI and runtime configuration
Design principles:
- Supervisor owns lifecycle and is the only place that calls waitpid for the container process
- Child becomes PID 1 inside the namespace and is responsible for reaping orphaned processes
- Isolation logic is strictly separated from runtime logic
- All namespace and filesystem setup happens before exec
-
Sigil starts as the supervisor process
-
It creates a child process using clone with namespace flags
-
The child blocks until the parent completes setup
-
The child configures isolation:
- mount namespace and private propagation
- pivot_root into container filesystem
- mount /proc
- attach to cgroup
-
The child becomes PID 1 and forks the target process
-
PID 1 reaps orphaned processes and exits with the child status
-
The supervisor forwards signals and waits for container exit
- Linux kernel with namespace and cgroup v2 support
- Root privileges or appropriate capabilities
- Rust toolchain
Prepare a minimal root filesystem:
mkdir -p rootfs/bin
cp /bin/sh rootfs/bin/
Run a container:
sudo cargo run -- --rootfs ./rootfs -- /bin/sh
Inside the container:
hostname
ps
The process list and hostname should be isolated from the host.
- Networking namespace not implemented
- No seccomp filtering
- No capability dropping
- Minimal cgroup support
- No OCI compatibility layer
- man 2 clone
- man 7 namespaces
- man 2 pivot_root
- man 7 cgroups
- runc source code