Pre-alpha — APIs, wire formats, and behavior may change without notice. Expect breaking changes; use with caution.
emberd

Architecture

The components, the request lifecycle, the runtime model, and the deliberate non-goals.

emberd is two binaries and a wire protocol between them: a host daemon that owns microVM lifecycle, and a guest agent that runs code inside each VM.

Components

ComponentLives inRole
emberd daemoncmd/emberdHost-side HTTP server. Owns microVM lifecycle, holds sandbox handles, dispatches exec over vsock.
emberd-initcmd/emberd-initPID 1 inside each microVM. Brings up the rootfs, serves the control protocol on vsock, runs submitted code.
HTTP APIpkg/apiRequest/response types and routing, wired to a sandbox.Manager.
Managerpkg/sandbox + pkg/sandbox/firecrackerThe Manager interface and its Firecracker-backed implementation.
Control protocolpkg/protoThe length-prefixed-JSON wire format shared by host and guest.
Guest initramfsrootfs/build.shA cpio archive whose /init is a static emberd-init.

The daemon and guest agent share exactly one package — pkg/proto — which keeps the contract between them explicit and small.

How a request flows

The host daemon routes HTTP through api.Server to the Manager, which dispatches Create, Exec, or Delete. Create boots a microVM over KVM; Exec sends an ExecRequest over vsock to the guest's AF_VSOCK listener and runExec, which returns an ExecResult; Delete SIGTERMs the VMM, discarding the tmpfs.

Each sandbox is exactly one firecracker process holding one microVM. The daemon keeps an in-memory handle (map[id]*vm) with the machine, its work directory, and the vsock socket path.

The runtime model

  • One microVM per sandbox. The strongest isolation and the simplest thing to reason about. A warm pool comes later (see Roadmap).
  • Cold boot today. Create boots a fresh VM: kernel + custom initramfs + a read-only rootfs drive. Snapshot restore (sub-100ms) is the v0.2 target.
  • vsock control plane. Host ↔ guest traffic (exec requests, output) goes over a virtio-vsock device, not a NIC. "No network" really means none — including for control.
  • Read-only base + tmpfs overlay. The language pack is an immutable squashfs; each sandbox layers a per-VM tmpfs on top via overlayfs. Base pages are shared, resets are trivial (discard the tmpfs), and snapshots stay small.

See Concepts for the detail behind each of these.

Sandbox identity

A sandbox ID looks like sb_a1b2c3d4e5f6 — an sb_ prefix plus 6 random bytes hex-encoded. Firecracker's instance --id only accepts [A-Za-z0-9-], so the daemon passes a hyphen-sanitized form (sb-a1b2c3d4e5f6) to the VMM while keeping the underscore form as the public/API identity. The two never need to match.

Per-sandbox state on the host

Everything for one sandbox lives under ${TMPDIR:-/tmp}/emberd/<id>/:

/tmp/emberd/sb_a1b2c3d4e5f6/
├── fc.sock      # Firecracker API socket
├── vsock.sock   # host end of the hybrid-vsock control channel
└── vm.log       # guest console + VMM log (great for debugging boots)

The directory is created on Create and removed on Delete.

Networking

  • v0.1: no network access inside sandboxes. No TAP, no DNS, no host loopback.
  • v0.2+: opt-in per-sandbox egress allowlist — likely a host TAP device plus iptables rules limiting destinations.

Non-goals

  • Persistent storage across sandbox lifetimes — use the host.
  • Cross-sandbox communication — each sandbox is sealed by design.
  • Built-in auth / multi-tenancy — assume the daemon is reached only on localhost or behind your own auth layer.

On this page