Encore built crackling, a Rust daemon and CLI that boots the same OCI images as lightweight Linux microVMs on both Linux (via Firecracker) and macOS (via Apple's Virtualization.framework), replacing four years of a shared remote build server workflow. The write-up covers the old setup's pain points (SSH-based deploys, hand-built Docker bridges, manual image squashing), the design of a backend-agnostic MachineBackend trait, threading constraints around VZ's serial dispatch queue, unwrapping EFI zboot kernels, building an in-process OCI-to-initramfs pipeline without root or loop mounts, vsock-based guest agent communication, and why VZ's snapshot save silently fails due to a private entitlement Apple withholds from third parties.
Table of contents
Four years of developing on a shared remote machineThe build system ran everywhere except our laptopsOne API over two hypervisors with little in commonThe one thread Apple's framework insists onBuilding a bootable Linux image without LinuxGetting a shell inside the VMApple does not let third parties snapshot a VMWhat runs on a Mac nowQuestions this post answers
Why does Apple's Virtualization.framework fail with VZErrorInternal when trying to save VM state, even though validateSaveRestoreSupport says it's supported?
Saving VM state requires the com.apple.private.virtualization entitlement, which Apple does not grant to third-party applications, while running a VM only needs the public com.apple.security.virtualization entitlement. Because the validator does not check for the private entitlement, it reports save/restore as supported, but the actual saveMachineStateToURL call fails with a generic VZErrorInternal, the same error a corrupt or compressed kernel produces. Anyone debugging VZ snapshot support can compare notes on entitlement gaps like this via daily.dev.
How do you boot an arm64 Linux kernel with Apple's Virtualization.framework when the distro only ships a compressed EFI zboot image?
Virtualization.framework requires an uncompressed raw arm64 Image and fails with a generic internal error if handed a compressed EFI zboot kernel, since there is no firmware present to decompress it. The fix is detecting the MZ and zimg signature bytes at the zboot header, reading the payload offset, size, and compression method from the header, and gunzipping the payload yourself before boot. Developers wiring up custom microVM boot paths track these low-level kernel format quirks on daily.dev.
Why won't Firecracker run on macOS?
Firecracker drives KVM directly, which requires a Linux host exposing /dev/kvm, something no Mac provides. Firecracker's maintainers considered a working proof of concept built on Apple's Virtualization.framework but rejected it and stated they do not plan to support macOS, leaving teams that develop on Macs to either run Firecracker remotely or build a separate hypervisor backend for macOS. Teams choosing a microVM stack for mixed Linux and macOS dev environments can follow tradeoffs like this on daily.dev.