forked from wrenn/wrenn
Remove Firecracker-specific MMDS metadata fetching and metrics host module. CH communicates with the guest purely over TAP networking, so MMDS (Firecracker's metadata service via MMDS address) is no longer needed. - Remove src/host/ module (mmds.rs, metrics.rs) - Remove reqwest dependency (was only used for MMDS HTTP calls) - Remove --isnotfc CLI flag (no longer dual-mode) - Simplify health endpoint and init handler - Update state management for CH snapshot lifecycle - Bump version to 0.3.0
envd (Rust)
Wrenn guest agent daemon — runs as PID 1 inside Cloud Hypervisor microVMs. Provides process management, filesystem operations, file transfer, port forwarding, and VM lifecycle control over Connect RPC and HTTP.
Rust rewrite of envd/ (Go). Drop-in replacement — same wire protocol, same endpoints, same CLI flags.
Prerequisites
- Rust 1.88+ (required by
connectrpc0.3.3) protoc(protobuf compiler, for proto codegen at build time)musl-tools(for static linking)
# Ubuntu/Debian
sudo apt install musl-tools protobuf-compiler
# Rust musl target
rustup target add x86_64-unknown-linux-musl
Building
Static binary (production — what goes into the rootfs)
cd envd-rs
ENVD_COMMIT=$(git rev-parse --short HEAD) \
cargo build --release --target x86_64-unknown-linux-musl
Output: target/x86_64-unknown-linux-musl/release/envd
Verify static linking:
file target/x86_64-unknown-linux-musl/release/envd
# should say: "statically linked"
ldd target/x86_64-unknown-linux-musl/release/envd
# should say: "not a dynamic executable"
Debug binary (dev machine, dynamically linked)
cd envd-rs
cargo build
Run locally (outside a VM):
./target/debug/envd --port 49983
Via Makefile (from repo root)
make build-envd # static musl release build
make build-envd-go # Go version (for comparison)
CLI Flags
--port <PORT> Listen port [default: 49983]
--version Print version and exit
--commit Print git commit and exit
--cmd <CMD> Spawn a process at startup (e.g. --cmd "/bin/bash")
--cgroup-root <PATH> Cgroup v2 root [default: /sys/fs/cgroup]
Endpoints
HTTP
| Method | Path | Description |
|---|---|---|
| GET | /health |
Health check, triggers post-restore |
| GET | /metrics |
System metrics (CPU, memory, disk) |
| GET | /envs |
Current environment variables |
| POST | /init |
Host agent init (token, env, mounts) |
| POST | /snapshot/prepare |
Quiesce before Cloud Hypervisor snapshot |
| GET | /files |
Download file (gzip, range support) |
| POST | /files |
Upload file(s) via multipart |
Connect RPC (same port)
| Service | RPCs |
|---|---|
| Process | List, Start, Connect, Update, StreamInput, SendInput, SendSignal, CloseStdin |
| Filesystem | Stat, MakeDir, Move, ListDir, Remove, WatchDir, CreateWatcher, GetWatcherEvents, RemoveWatcher |
Architecture
42 files, ~4200 LOC Rust
Binary: ~4 MB (stripped, LTO, musl static)
src/
├── main.rs # Entry point, CLI, server setup
├── state.rs # Shared AppState
├── config.rs # Constants
├── conntracker.rs # TCP connection tracking for snapshot/restore
├── execcontext.rs # Default user/workdir/env
├── logging.rs # tracing-subscriber (JSON or pretty)
├── util.rs # AtomicMax
├── auth/ # Token, signing, middleware
├── crypto/ # SHA-256, SHA-512, HMAC
├── host/ # System metrics
├── http/ # Axum handlers (health, init, snapshot, files, encoding)
├── permissions/ # Path resolution, user lookup, chown
├── rpc/ # Connect RPC services
│ ├── pb.rs # Generated proto types
│ ├── process_*.rs # Process service + handler (PTY, pipe, broadcast)
│ ├── filesystem_*.rs # Filesystem service (stat, list, watch, mkdir, move, remove)
│ └── entry.rs # EntryInfo builder
├── port/ # Port subsystem
│ ├── conn.rs # /proc/net/tcp parser
│ ├── scanner.rs # Periodic TCP port scanner
│ ├── forwarder.rs # socat-based port forwarding
│ └── subsystem.rs # Lifecycle (start/stop/restart)
└── cgroups/ # Cgroup v2 manager (pty/user/socat groups)
Updating the rootfs
After building the static binary, copy it into the rootfs:
bash scripts/update-debug-rootfs.sh [rootfs_path]
Or manually:
sudo mount -o loop /var/lib/wrenn/images/minimal.ext4 /mnt
sudo cp target/x86_64-unknown-linux-musl/release/envd /mnt/usr/bin/envd
sudo umount /mnt