Implements the hypervisor design's Phase 1: a second runtime.Runtime
backend (QEMU) that runs each service component as a Nanos unikernel VM
instead of a podman container, selected per-component via a new
runtime = "unikernel" service-def field.
- internal/runtime/qemu.go: QEMURuntime. Pull extracts the ELF from the
OCI image; Run does `ops build` + boots qemu-system-x86_64 with KVM,
user-mode net port-forwards, QMP control socket and serial console log;
Stop/Remove/Inspect/List/Logs map onto VM lifecycle + state dir.
- proto/registry/servicedef: add runtime, memory_mb, vcpus fields
(registry migration 5).
- agent: holds both runtimes; runtimeFor() selects per component;
listAllContainers() merges containers + VMs so drift/status see both.
Unikernel runtime auto-enables on nodes with /dev/kvm + ops.
Validated end-to-end on straylight: a test service deploys via
`mcp deploy --direct`, boots as a Nanos unikernel, serves HTTP through
the agent port-forward, and reports running via `mcp status`/`mcp logs`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Master struct with Run() lifecycle following the agent pattern exactly:
open DB → bootstrap nodes → create agent pool → DNS client → TLS →
auth interceptor → gRPC server → signal handler.
RPC handlers:
- Deploy: place service (tier-aware), forward to agent, register DNS
with Tailnet IP, detect public routes, validate against allowed
domains, coordinate edge routing via SetupEdgeRoute, record placement
and edge routes in master DB, return structured per-step results.
- Undeploy: undeploy on worker first, then remove edge routes, DNS,
and DB records. Best-effort cleanup on failure.
- Status: query agents for service status, aggregate with placements
and edge route info from master DB.
- ListNodes: return all nodes with placement counts.
Placement algorithm: fewest services, ties broken alphabetically.
DNS client: extracted from agent's DNSRegistrar with explicit nodeAddr
parameter (master registers for different nodes).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>