Skip to main content
Run microsandbox inside your application container using the worker’s KVM device. This guide creates a sandbox, shares files, runs a command, and cleans up.
This example uses a privileged container with broad node access. Use a dedicated test node, and run untrusted code only inside the microVM.

Prerequisites

  • A Linux worker with usable /dev/kvm; virtual workers need nested virtualization.
  • A namespace that permits privileged pods and host device mounts.
  • An application image matching the worker’s architecture: amd64 or arm64.
  • Docker, kubectl access, and a registry the worker can pull from.
  • Pod egress for downloading the guest image.
Check the device on the Linux worker:
The application must be able to open this device and issue KVM ioctls.
Native macOS microsandbox uses Apple’s hypervisor; Linux containers need KVM. Neither CPU emulation nor enabling Kubernetes supplies missing KVM support.

Build the application

This sample application runs a command in a sandbox with a shared workspace.
In an empty directory, save agent.py:
agent.py
Volume.bind() reads a path inside the application container. Here, a Kubernetes volume is shared at /workspace in both the container and guest; application files need no node hostPath.Add Dockerfile:
Dockerfile
The wheel bundles the runtime and kernel firmware. No Docker daemon is needed inside the pod.
Replace REGISTRY/PROJECT here and in the manifest, then build and push:
For x86-64 workers, use --platform linux/amd64. Private application images need Kubernetes imagePullSecrets; private guest images need separate microsandbox registry credentials.

Run the pod

Label the KVM-capable worker and create a test namespace:
The label does not detect KVM. Your namespace must already permit this pod’s security settings. Save pod.yaml with your image reference:
pod.yaml
For x86-64, change kubernetes.io/arch to amd64. CharDevice requires an existing KVM device. Host networking, host PID access, and container-engine sockets are unnecessary. Apply and wait for completion:
Allow extra time for the first guest-image download. The wait command does not exit early when a pod fails. To investigate before the timeout, press Ctrl-C and run the troubleshooting commands; this stops waiting, not the pod. Expected output:
The guest reads the input and writes the output. After the command finishes, the context manager kills and removes the sandbox. The application reads the shared output, then the pod reaches Succeeded. To rerun, delete the pod and reapply. To clean up:
Remove the label only if you added it and no other workloads use it.

Device plugins

A device plugin can expose KVM as a schedulable resource and grant device access. A hostPath mount alone may leave unprivileged containers blocked by runtime device rules. With a KVM plugin installed:
  1. Find its resource name and capacity with kubectl describe node YOUR_KVM_NODE.
  2. Request the resource in container limits as the plugin documents. Names such as devices.kubevirt.io/kvm are plugin-specific.
  3. Remove the kvm volume and mount; the plugin supplies the device.
  4. Remove privileged: true and verify sandbox boot, device permissions, and seccomp/AppArmor/SELinux compatibility. Device access alone does not prove VM startup works.
Plugin privileges are separate from application privileges. One KVM allocation does not limit VM count; bound concurrency in your application.

Operational notes

  • Files: emptyDir survives container restarts but not pod deletion. Use a PVC for durable output and Volume.bind(path, readonly=True) for protected inputs.
  • Runtime state: keep /msb private to each pod. It contains the database, image cache, and sandbox files. Persisting it does not preserve running VMs.
  • Resources: budget for the application, all guests, and runtime overhead. This example allows 2 GiB for one 512 MiB guest. Measure concurrent workloads and disk usage; keep runtime volumes disk-backed.
  • Networking: both cluster egress rules and microsandbox policies apply. Guest images download through the application container.
  • Shutdown: the context manager kills and removes the sandbox on exit. For graceful shutdown, call await sandbox.stop() before leaving the context. Long-running applications need a SIGTERM handler that stops accepting work, finishes or cancels tasks, and awaits shutdown within the pod’s grace period. Default signal handling does not unwind Python contexts. No sandbox survives pod deletion.

Troubleshooting

To run a diagnostic instead of the application, add this under the agent container in pod.yaml:
Delete the existing pod, reapply the manifest, and read the diagnostic output:
Check the KVM device and access results. Passing these checks does not guarantee microVM boot. Remove command, then delete and recreate the pod to run the application again.

Validation status

Checked: ARM64/AMD64 image builds, OrbStack guest-image pulls, Kubernetes v1.34 schema, and native macOS file sharing, read-only mounts, cleanup, and concurrency. Kubernetes microVM execution remains unverified: the test OrbStack VM lacked /dev/kvm. A KVM-capable Linux worker is still needed to validate boot, admission, and device-plugin setup.