Self-hosted secure VM sandboxes for AI compute at scale
build / run inside VM sandboxes (docker sidecar on kfd, kql, and k7d; see [PERFORMANCE.md](PERFORMANCE.md))
- β‘ Warm VM fork on the k7d backend: k7 fork CoW-clones a running sandbox's disk and memory in ~5 ms at the VMM; end-to-end through k7/Kubernetes is ~2 s to a Ready pod
- π Multi-node clusters (Ansible + Longhorn)
- π Cilium CNI with FQDN egress policies
- πΈ Pause / resume / fork / restore and k7 snapshot lifecycle
- π Python SDK: pip install k7-sdk (katakate package deprecated)
π **See [ROADMAP.md](ROADMAP.md) for upcoming work (GPU passthrough, β¦).**
Note: Katakate is currently in beta and under security review. Use with caution for highly sensitive workloads.
# Usage For usage you need: - **Node(s)** that will host the VM sandboxes - **Client** from where to send requests We provide a: - **CLI**: to use on the node(s) directly --> `apt install k7` - **API**: deployed automatically by `k7 install` (toggle with `k7 api enable` / `k7 api disable`) - **Python SDK**: HTTP client sync/async --> `pip install k7-sdk` ## Current requirements ### For the node(s) - Ubuntu (amd64 or arm64) host. - **`k7d` backend is amd64 / x86_64 only** (same ISA; Debian calls it `amd64`, the release tarball is `*-x86_64-linux.tar.gz`). `kfd` and `kql` support amd64 and arm64. - Hardware virtualization (KVM) available and accessible - Check: `ls /dev/kvm` should exist. - This is typically available on your own Linux machine. - On cloud providers, it varies. - Hetzner (the only one I tested so far) yes for their `Robot` instances only, i.e. "dedicated": robot.hetzner.com. - AWS: only `.metal` EC2 instances. - GCP: virtualization friendly, most instances, with `--enable-nested-virtualization` flag. - Azure: Dv3, Ev3, Dv4, Ev4, Dv5, Ev5 (Intel/AMD x86) or Dpdsv5, Dpldsv5, Epsv5 (ARM64). - DigitalOcean: Premium Intel and AMD droplets with nested virtualization enabled. - Others: in general, hardware virtualization is not exposed on cloud VPS, so you'll likely want a dedicated / bare metal. - One raw disk (unformatted, unpartitioned) for the thin-pool that k7 will provision for efficient disk usage of sandboxes. - Use `./utils/wipe-disk.sh /your/disk` to wipe a disk clean before provisioning. DANGER: destructive - it will remove data/partitions/formatting/SWRAID. - Ansible (for installer): ```bash sudo add-apt-repository universe -y sudo apt update sudo apt install -y ansible ``` - Docker and Docker Compose (for the API): ```bash curl -fsSL https://get.docker.com | sh ``` Already tested setups: - Hetzner Robot dedicated with Ubuntu 24.04 and a **spare raw NVMe** for the `kfd` thin-pool. Dual-NVMe boxes (no third drive): install the OS on one disk only β see [tutorials/k7_hetzner_node_setup.md](tutorials/k7_hetzner_node_setup.md). (Older PDF that assumed an add-on third NVMe: [tutorials/k7_hetzner_node_setup.pdf](tutorials/k7_hetzner_node_setup.pdf).) ### For the client Recent Python, or the **`k7`** CLI / **`k7-sdk`** from a Linux node or your laptop (API URL + key). #### Development on macOS The **`.deb` / PPA package is Linux-only** (amd64/arm64). On a MacBook: - **CLI from source:** `./src/k7/cli/dev.sh` (same commands as `k7`; uses `uv` + `PYTHONPATH=src`) - **API client from laptop:** set `K7_API_URL` and `K7_API_KEY`, then `dev.sh create` / `dev.sh list` (no `--core`) - **`k7 install`** targets Linux servers with KVM β run on the node or via SSH, not on macOS locally - **`pip install k7-sdk`** for Python scripts only Do not install the Ubuntu `.deb` on macOS. ## Quick Start ### Get your node(s) ready First install `k7` on your Linux server that will host the VMs: ```shell sudo add-apt-repository ppa:katakate.org/k7 sudo apt update sudo apt install k7 ``` Then let `k7` get your node ready with everything: ```console $ k7 install --backend kfd,kql,k7d --k7d-version 0.2.1 Current task: Reminder about logging out and back in for group changes Installing K7 on 1 host(s)... ββββββββββββββββββββββββββββββββββββββββ 100% 0:01:41 β Installation completed successfully! ``` Optionally pass `-v` for a verbose output. > Dual-NVMe Hetzner boxes have no third empty disk for the `kfd` thin-pool. > Put Ubuntu on **one** NVMe (`SWRAID 0` / `TWO_DISK=1`) and leave the other > raw β the playbook auto-detects that spare. Do **not** pin > `--disk /dev/nvme1n1`: NVMe names swap across reboots. Walkthrough: > [tutorials/k7_hetzner_node_setup.md](tutorials/k7_hetzner_node_setup.md) > (this file is also in public [Katakate/k7](https://github.com/Katakate/k7)). > > `k7` 0.2.1 from the PPA still defaults the k7d artifact to 0.1.0. Pass > `--k7d-version 0.2.1` so install pulls the current > [Katakate/k7d](https://github.com/Katakate/k7d/releases/tag/v0.2.1) release. > Multi-node inventory shapes (2-node server+agent, 3-node `--ha`) are in > `src/k7/deploy/inventory.ini.example`. This will install and most importantly connect together the following components (depending on `--backend`): - Kubernetes (K3s prod-ready distribution) - Kata (for container virtualization) - Firecracker + Jailer + devmapper thin-pool (`kfd`) - QEMU via Kata + Longhorn PVC-backed roots (`kql`) - k7d daemon + `containerd-shim-k7-v1` + RuntimeClass `k7` (`k7d`) Careful design: config updates will not touch your existing Docker or containerd setups. We chose to use K3s' own containerd for minimal disruption. Installation may however overwrite existing installations of K3s, Kata, Firecracker, Jailer, QEMU/Kata config, or Longhorn. ### CLI Usage You can run workloads directly from the node(s) using the CLI. To create a sandbox, just create a yaml config for it. #### k7.yaml example: ```yaml name: my-sandbox-123 image: alpine:latest namespace: default # Optional: restrict egress (safe pattern: whitelist only your own egress proxy IP) egress_whitelist: - "10.0.0.5/32" # Your private egress proxy/gateway # Optional: resource limits limits: cpu: "1" memory: "1Gi" ephemeral-storage: "2Gi" # Optional: run before_script inside the container once at start. Network restrictions apply after the before-script, so you can install packages here, pull git repos, etc before_script: | apk add --no-cache git curl # Optional: load environment variables from a file. These will be available both during the before-script, and in the sandbox env_file: path/to/your/secrets/.env ``` #### Running commands ```bash # Create a sandbox (uses k7.yaml in the current directory by default, but you can also pass: -f myfile.yaml) k7 create # Or pick a backend explicitly (kfd | kql | k7d β aliases for the full names) k7 create -f k7.yaml --backend k7d # List sandboxes k7 list # Delete a sandbox k7 delete my-sandbox-123 # Delete all sandboxes. You can also pass a namespace k7 delete-all ``` #### Fork / pause / snapshot ```bash # Warm CoW fork (disk + memory) β source must be a k7d sandbox k7 create -f k7.yaml --backend k7d # name from yaml, e.g. my-sandbox-123 k7 exec my-sandbox-123 sh -c 'echo hi > /tmp/state.txt' k7 fork my-sandbox-123 branch-a k7 exec branch-a cat /tmp/state.txt # inherited memory + disk # Disk-only fork (cold boot from cloned PVC) β kql / kata-qemu-longhorn k7 create -f k7.yaml --backend kql k7 fork my-sandbox-123 branch-b # optional: pin the Longhorn VolumeSnapshot name used for the clone k7 fork my-sandbox-123 branch-c --snapshot my-snap # Parallel branches from one base for i in $(seq 0 7); do k7 fork my-sandbox-123 exp-$i & done; wait # Pause / resume (kql keeps the PVC; k7d freezes the live VM) k7 pause my-sandbox-123 k7 resume my-sandbox-123 # Named disk snapshot without pausing (kql) k7 snapshot create my-sandbox-123 my-named-snap ``` On **k7d**, the VMM fork itself is ~5 ms; end-to-end through Kubernetes to a Ready pod is ~2 s. On **kql**, fork is a Longhorn snapshot + PVC clone + cold boot (~45 s). See [PERFORMANCE.md](PERFORMANCE.md) and [docs/BACKENDS.md](docs/BACKENDS.md). ### API usage The K7 API is deployed automatically by `k7 install` as the `k7-api` Deployment in `kube-system`. K3s keeps it running on its own; there's no separate "start" step. ```shell # Check status + endpoint k7 api status k7 api endpoint # Generate API key k7 generate-api-key my-key1 # Temporarily disable / re-enable k7 api disable k7 api enable ``` Generating / listing / revoking keys talks to `/etc/k7/api_keys.json`, so those subcommands need to run on the node (typically `sudo` or `root`). ### Python SDK Usage After your k7 API is up, usage is very simple. Install the Python SDK via: ```shell pip install k7-sdk ``` Or if you want async support: ```shell pip install "k7-sdk[async]" ``` The legacy `katakate` PyPI name remains as a one-release shim that re-exports `k7_sdk` with a deprecation warning. Then use with: ```python from k7_sdk import Client k7 = Client( endpoint='https://