Warning: This project is almost entirely AI-generated and has not been human-reviewed line by line. Use it at your own risk, especially when running as root (which it requires). A thorough human review will be done when time permits. Contributions, testing, and code review are very welcome.
TCR is a minimal container runtime designed for resource-limited embedded devices. It uses crun as the low-level OCI runtime and squashfs as the image format.
┌──────────┐ ┌──────────┐
│ tcr │──RPC───▶│ tcrd │
│ (client) │ │ (daemon) │
└──────────┘ └──────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
containers images networks
(crun) (squashfs) (nftables)
- tcr — thin CLI client, no business logic, forwards commands over a Unix domain socket
- tcrd — the daemon, manages containers, images, and networks
Build:
- C compiler (gcc or clang)
- CMake ≥ 3.10
- libtev (event loop, build from source — see below)
- libcjson, libuuid
- libnl-3, libnl-route-3
- libnftables
- libxxhash
Runtime:
- Linux kernel with: overlayfs, squashfs, loop devices, network namespaces, nftables
- crun
Image creation (build machine only):
- skopeo, umoci, mksquashfs (squashfs-tools with zstd support)
libtev is not available as a system package and must be built from source:
git clone --recursive https://github.com/chemwolf6922/tiny-event-loop.git /tmp/tev
cd /tmp/tev
make -j$(nproc)
sudo make install
sudo ldconfigmkdir -p build && cd build
cmake ..
make -j$(nproc)This produces two binaries: tcr (client) and tcrd (daemon).
# Install binaries to /usr/bin
sudo make install
# Install and enable the service (systemd or busybox init, auto-detected)
sudo make install-serviceOverride init system detection: cmake .. -DINIT_SYSTEM=busybox
# Remove binaries and service files, keep data
sudo make uninstall
# Remove everything: binaries, service, data, network artifacts
sudo make nuke./host_tools/tcr-create-image.sh docker.io/library/alpine:latest alpine_latest.sqfsThis pulls the image, flattens it, and packages it into a squashfs file.
sudo tcrdOr via the service:
sudo systemctl start tcrd # systemd
sudo /etc/init.d/tcrd start # busybox initsudo tcr image load ./alpine_latest.sqfs
# sha256:1529d13528ed05668b2038ffab807ac8633ad6adfe6be8901adda62411f70d29# Interactive shell
sudo tcr run alpine /bin/sh
# Detached container with port forwarding
sudo tcr run -d --name web -p 8080:80 nginx
# Read-only, no network
sudo tcr run --no-network --read-only alpine cat /etc/os-releasetcr run [options] <image> [command...] # Create and run a container
tcr ps # List containers
tcr stop <name_or_id> # Graceful stop (SIGTERM → SIGKILL)
tcr kill <name_or_id> # Immediate stop (SIGKILL)
tcr rm <name_or_id> # Remove a container| Flag | Description |
|---|---|
-d |
Run in detached mode (background) |
--name <name> |
Assign a name to the container |
--rm |
Auto-remove on exit |
--read-only |
Read-only rootfs (no overlay) |
-t |
Allocate a pseudo-TTY |
-e KEY=VALUE |
Set environment variable (repeatable) |
-v src:dst[:ro] |
Bind mount (repeatable) |
--tmpfs dst[:size] |
tmpfs mount (repeatable) |
-p [hostIP:]hostPort:containerPort[/tcp|udp] |
Port forwarding (repeatable) |
--network <name> |
Join a named NAT network (default: tcr_default) |
--no-network |
Disable networking |
--restart <policy> |
Restart policy: no, unless-stopped, always |
--stop-timeout <sec> |
Graceful stop timeout in seconds (default: 10) |
tcr image load <path> # Load a squashfs image
tcr image ls # List loaded images
tcr image rm <ref> # Remove an image (by digest or name:tag)tcr network ls # List NAT networks
tcr network rm <name> # Remove a NAT networktcr help # Show usageEvery container joins a NAT network by default (tcr_default), which provides:
- Internet access via nftables masquerade
- Inter-container DNS discovery (containers can reach each other by name)
- Port forwarding to the host (
-p)
Use --no-network to disable, or --network <name> to use a named network.
All daemon state lives under /var/lib/tcr (configurable with tcrd --root <path>):
/var/lib/tcr/
├── images_root/ # mounted squashfs images
├── networks/ # NAT network state
└── containers/ # container dirs (overlay, config, metadata)
cd test/build && cmake .. && make -j$(nproc)
# Integration test (requires root, pulls alpine image on first run)
sudo ./run_test_tcrd.sh
# Unit tests (no root needed)
./test_rpc
./test_seccomp_resourceThe core runtime is functional: image loading, container lifecycle, NAT networking, port forwarding, DNS discovery, and the daemon are all implemented and tested.
See todo.md for planned features (exec, logs).