Kata Containers & Block Storage
In production Kubernetes clusters, CubePod runs each sandbox inside a dedicated Kata Containers microVM backed by two CSI raw Block PVCs (/dev/cubepod-rootfs and /dev/cubepod-workspace). Hardware virtualization ensures kernel, mount-namespace, and device isolation for untrusted agent workloads, while thin raw block storage unlocks fast snapshot cloning (POST /sandboxes/{id}/fork) and persistent OverlayFS state across pause/resume cycles.
Step 1: Configure containerd for Kata + Block Devices
Section titled “Step 1: Configure containerd for Kata + Block Devices”Every worker node running sandboxes needs KVM support (/dev/kvm with vmx or svm), containerd, containerd-shim-kata-v2, and kata-runtime.
CubePod ships an automated configuration helper at deploy/k8s/kata/configure-containerd-kata.sh:
# Preview changes without modifying the nodesudo bash deploy/k8s/kata/configure-containerd-kata.sh --dry-run
# Apply configuration and restart containerdsudo bash deploy/k8s/kata/configure-containerd-kata.sh --restartSupported flags:
| Flag | Default / Purpose |
|---|---|
--dry-run |
Print planned edits without modifying config files |
--config-path <path> |
Path to containerd config (default /etc/containerd/config.toml) |
--kata-config-path <path> |
Override the Kata configuration file path referenced by the shim |
--allow-missing-kvm |
Continue validation even if /dev/kvm is absent (for non-nested test setups) |
--restart |
Restart containerd after writing updated configuration |
Why privileged_without_host_devices Is Required
Section titled “Why privileged_without_host_devices Is Required”Inside each sandbox pod, podd-init runs as PID 1 with privileges to run e2fsck, mkfs.ext4, mount, OverlayFS setup, and pivot_root on /dev/cubepod-rootfs and /dev/cubepod-workspace. configure-containerd-kata.sh sets two critical flags on the Kata runtime handler in /etc/containerd/config.toml:
privileged_without_host_devices = trueprivileged_without_host_devices_all_devices_allowed = true
Without these settings, containerd attempts to bind-mount every host /dev/* node into the privileged container inside the Kata guest, causing device conflicts such as /dev/full: EEXIST during pod startup.
Step 2: Apply Kata RuntimeClass Manifests
Section titled “Step 2: Apply Kata RuntimeClass Manifests”Label GPU/KVM-capable worker nodes (kubectl label node <node> katacontainers.io/kata-runtime=true) and apply deploy/k8s/kata/runtimeclasses.yaml:
kubectl apply -f deploy/k8s/kata/runtimeclasses.yamlThe manifest defines two RuntimeClass options selectable via Helm runtime.runtimeClassName:
| RuntimeClass | Handler | Fixed Pod Overhead (cpu / memory) |
Node Selector |
|---|---|---|---|
kata-qemu |
kata-qemu |
250m / 160Mi |
katacontainers.io/kata-runtime: "true" |
kata-clh |
kata-clh |
250m / 128Mi |
katacontainers.io/kata-runtime: "true" |
Step 3: Provision Raw Block CSI Storage
Section titled “Step 3: Provision Raw Block CSI Storage”CubePod requires a CSI driver supporting volumeMode: Block and ideally fast snapshot/CoW cloning for fork. Pick either Longhorn V2 (SPDK) or OpenEBS LVM-LocalPV.
Option A: Longhorn V2 (SPDK NVMe-oF + Fast Clones)
Section titled “Option A: Longhorn V2 (SPDK NVMe-oF + Fast Clones)”Longhorn V2 runs an SPDK user-space storage engine (v2DataEngine) capable of fast thin provisioning and copy-on-write cloning. Scripts under deploy/k8s/longhorn-v2/ automate single-node or multi-node bring-up:
bash deploy/k8s/longhorn-v2/install.shWhat prep-node.sh and install.sh configure:
- Kernel modules & loopback block backing (
prep-node.sh):- Loads
nvme-tcp,nvme-fabrics,uio,uio_pci_generic, andvfio-pci. - Creates a sparse backing file at
$CUBEPOD_LONGHORN_IMG(default/storage/cubepod/longhorn-v2.img, size80G), attaches it vialosetup --direct-io=on, symlinks/dev/cubepod/longhorn-v2, installscubepod-longhorn-loop.service, and reserves2Mihugepages (CUBEPOD_HUGEPAGES, default1024).
- Loads
- Cluster preparation & Helm installation (
install.sh):- Labels the target node
cubepod.io/longhorn-v2=trueand executes thecubepod-longhorn-v2-prepjob (node-prep-job.yaml). - Optionally restarts
kubeletifCUBEPOD_RESTART_KUBELET=1is set so kubelet recognizes hugepages immediately. - Installs Helm chart
longhorn/longhorn(--version 1.8.2) into namespacelonghorn-systemusingdeploy/k8s/longhorn-v2/values.yaml(v1DataEngine: false,v2DataEngine: true,v2DataEngineCPUMask: "0x1",v2DataEngineGuaranteedInstanceManagerCPU: 1000). - Patches
nodes.longhorn.io/<node>with adiskType: blockdisk taggedcubepod-v2and appliesdeploy/k8s/longhorn-v2/storageclass.yaml:
- Labels the target node
| Field | Value in storageclass.yaml |
|---|---|
metadata.name |
longhorn-v2-block-thin |
provisioner |
driver.longhorn.io |
parameters.numberOfReplicas |
"1" |
parameters.dataEngine |
v2 |
parameters.diskSelector |
cubepod-v2 |
allowVolumeExpansion |
true |
volumeBindingMode |
Immediate |
Option B: OpenEBS LVM-LocalPV (Bare NVMe Volume Group)
Section titled “Option B: OpenEBS LVM-LocalPV (Bare NVMe Volume Group)”If your nodes have a dedicated local NVMe device and you prefer local LVM thin/thick provisioning without SPDK:
# On each worker node with raw disk /dev/nvme1n1:sudo pvcreate /dev/nvme1n1sudo vgcreate cubepod-vg /dev/nvme1n1
# Install operator and CubePod StorageClass:kubectl apply -f deploy/k8s/openebs-lvm-operator.yamlkubectl apply -f deploy/k8s/cubepod-lvm-sc.yamldeploy/k8s/cubepod-lvm-sc.yaml creates StorageClass cubepod-lvm-block (provisioner: lvm.csi.openebs.io, storage: "lvm", volgroup: "cubepod-vg", volumeBindingMode: Immediate, allowVolumeExpansion: true). Point storage.storageClassName: "cubepod-lvm-block" in your Helm values file when using OpenEBS LVM.
Step 4: Live Cluster Verification & Performance Benchmarks
Section titled “Step 4: Live Cluster Verification & Performance Benchmarks”Before running Kubernetes verification suites, copy deploy/k8s/env.example to deploy/k8s/env.local and adjust KUBECONFIG, storage class, and runtime settings (Makefile targets source deploy/k8s/env.local automatically).
Functional E2E & Block Suites
Section titled “Functional E2E & Block Suites”# Offline unit checks for K8s E2E helpersgo test -race -v ./test/k8s-e2e/...
# Live cluster block CSI & Kata pod lifecycle suitemake test-k8s-block # alias: make test-k8s-longhorn-v2
# Full live Kubernetes E2E suitemake test-k8s-e2eBenchmark Suite & Target SLOs
Section titled “Benchmark Suite & Target SLOs”Run TestK8sPerformanceBenchmark against your live cluster to profile cold boot, execution latency, archive sync, pause/auto-resume, RootFS reset, CoW fork, and WarmPool claim speeds:
CUBEPOD_K8S_BENCH=1 \CUBEPOD_BENCH_ITERATIONS=3 \CUBEPOD_BENCH_OUT=/tmp/cubepod-kata-benchmark.md \ go test -v -timeout 20m ./test/k8s-e2e/ -run TestK8sPerformanceBenchmarkThe benchmark suite tracks the following operations and CubePod SLO targets documented in deploy/k8s/kata/README.md:
| Benchmark Operation | Target SLO | What It Measures |
|---|---|---|
cold_create |
— | End-to-end cold sandbox pod boot (PodBox + PVC bind + Kata + podd ready) |
exec_foreground_rtt |
— | Foreground command round-trip latency over Gateway → podd |
archive_sync |
< 100ms |
Compressed tar.gz workspace upload & streaming extraction via podd |
pause / pause_auto_resume |
< 1500ms |
Pod scale-down followed by transparent wake-up via POST /connect or subdomain traffic |
reset_rootfs |
— | Incrementing rootfsGeneration and clearing OS state while keeping /workspace intact |
cow_fork |
< 1500ms |
CSI block snapshot clone into a newly booted child sandbox |
warmpool_prewarm / warmpool_claim_e2e |
< 200ms E2E HTTP (< 50ms controller overhead) |
Pre-warmed microVM claim latency through the Gateway |
Next Steps
Section titled “Next Steps”- Review the Kubernetes & Helm Deployment guide to customize controller and gateway replicas.
- Read Lifecycle, WarmPool & CoW Fork to understand how
PodWarmPoolandcow_forkinteract under the hood.