vhaudiquet b6ddd85525 feat(rootfs): cache-aware rootfs preparation with persist hook
Add ecr::rootfs with the full rootfs lifecycle behind the library:

- RootfsCache::prepare resolves an image reference, downloads through
  the tarball cache (with the OCI :latest digest freshness check) and
  extracts into a scratch directory tracked by PreparedRootfs.
- PreparedRootfs::persist packs the current rootfs back into its cache
  entry (compressed to match the entry's extension, symlinks and
  permissions preserved) and marks it with a .provisioned sidecar.
- RootfsCache::prepare_provisioned composes both into the hot-cell
  flow: provision once, and every later call sharing the cache skips
  the download and the provisioning step.

extract: an "oci-" cache entry without a layers.manifest is a
persisted provisioned rootfs; extract it as a plain archive.

The CLI now drives prepare and drops its inline cache/orchestration
code and the dirs/tempfile dependencies.  The binfmt check moves ahead
of the download so foreign-arch runs fail before pulling an image.
2026-09-21 00:06:20 +02:00
2026-06-09 19:47:23 +02:00
2026-06-08 18:44:10 +02:00

ecr - ephemeral chroot

Instantly drop into a disposable Linux environment on your host machine.
No Docker daemon. No VM. No root. Just namespaces.

ecr debian          # interactive Debian shell
ecr alpine:3.23     # specific Alpine version
ecr ubuntu:noble    # Ubuntu by codename
ecr fedora          # any Docker Hub image

How it works

ecr pulls a root filesystem (Alpine/Ubuntu direct from their CDNs; everything else from Docker Hub), extracts it into a temporary directory, and execs a shell inside a user + mount + PID + UTS namespace. The process tree is isolated, the rootfs is discarded on exit, and your host is never touched.

Usage

ecr [OPTIONS] <DISTRO[:VERSION]> [-- COMMAND...]
Argument Description
ubuntu, alpine, debian, fedora, … Distribution to enter
:version Optional version tag — codename, number, or latest / lts / edge
-- cmd arg… Run a command instead of an interactive shell

Options

Flag Description
--bind <PATH> Overlay-mount a directory read-only inside the chroot (default: current directory at /root/<name>)
--bind-rw <PATH> Bind-mount a directory read-write at /mnt/<name>
--no-bind Skip all directory mounts
--no-cache Force a fresh download, bypassing the cache
-v, --verbose Print diagnostic output (URLs, layer info, extraction steps)
-a, --arch <ARCH> Target architecture (amd64, arm64, armhf, riscv64, …)
--kernel[=PATH] Boot with QEMU system emulation. Downloads Alpine's linux-virt kernel if no =PATH given
-m, --memory <SIZE> Memory for QEMU VM (default: 2G, only with --kernel)

Examples

# Quick shell in the latest Debian
ecr debian

# Run a one-shot command
ecr alpine -- sh -c 'apk add curl && curl -s https://example.com'

# Work on your project inside Ubuntu — changes are visible on the host
ecr ubuntu --bind-rw ~/projects/myapp

# Native-compile for ARM64 through emulation (requires QEMU binfmt_misc)
ecr --arch arm64 alpine -- uname -m

# Always pull a fresh image
ecr --no-cache fedora

# Boot with QEMU system emulation (auto-downloads default kernel)
ecr --kernel alpine

# Boot with your own kernel (note the `=` — a space would parse the path as the distro)
ecr --kernel=/boot/vmlinuz ubuntu

# Boot with custom memory
ecr --kernel --memory 4G alpine

QEMU System Mode

When --kernel is specified, ecr boots the rootfs in a full QEMU virtual machine instead of using namespaces:

# Auto-download Alpine's linux-virt kernel (recommended)
ecr --kernel alpine

# Use your own kernel
ecr --kernel=/boot/vmlinuz ubuntu

This mode:

  • Creates an uncompressed CPIO initramfs from the rootfs (streamed to disk)
  • Boots QEMU with your kernel (or auto-downloads Alpine's linux-virt kernel)
  • Provides full VM isolation
  • Works for any architecture (no binfmt_misc needed)
  • Caches the default kernel in ~/.cache/ecr/

Host bind mounts (--bind, --bind-rw) are not applied in this mode.

Requirements:

  • qemu-system-<arch> installed
  • For custom kernels: kernel must have serial console support

Supported distributions

Name Source Version examples
alpine Alpine CDN latest, stable, edge, 3.23, 3.22
ubuntu Ubuntu CDN latest, lts, noble, 24.04
debian fedora arch gentoo Docker Hub latest, any tag
Any Docker Hub / OCI image Registry org/image:tag, ghcr.io/…, localhost:5000/…

Cache

Downloaded images are cached in ~/.cache/ecr/. For latest OCI tags the registry manifest digest is checked on each run — the image is only re-downloaded when it has actually changed. Use --no-cache to force a fresh pull regardless.

Requirements

  • Linux kernel ≥ 5.1
  • Unprivileged user namespaces enabled (/proc/sys/kernel/unprivileged_userns_clone = 1 on some distros)
  • newuidmap / newgidmap in $PATH
  • An entry in /etc/subuid and /etc/subgid for your user
  • For foreign-arch: QEMU user-mode emulation registered with binfmt_misc
S
Description
Ephemeral chroot into any distribution
Readme
865 KiB
Languages
Rust 100%