k7 lets you run secure VM sandboxes on Kubernetes — Firecracker, QEMU + Longhorn, or k7d (natively or under the Firecracker jailer). This Quickstart gets you from zero to a working sandbox via CLI and Python SDK.
If you already installed k7 previously, consider running make uninstall before reinstalling to avoid stale cached files in a previous .deb.
Requirements#
- Ubuntu host with hardware virtualization (KVM)
- Check:
ls /dev/kvmshould exist kfdandkql: amd64 or arm64.k7dandk7d-fcare amd64 / x86_64 only.- Cloud guidance: AWS
.metal, GCP (enable nested virtualization), Azure D/Ev series; typical VPS often lack KVM. Hetzner: Robot dedicated only (not Cloud VPS).
- Check:
- For the
kfd(Firecracker) backend: one raw, unformatted disk for the LVM thin-pool.kql,k7d, andk7d-fcdo not need a spare disk. - No Docker and no source checkout. 0.5.0 deploys the signed GHCR
k7-apiimage by digest (images.lock.yaml, cosign-verified). Buildingk7-api:localfrom a checkout, which 0.4.0 did by default, is opt-in withk7 install --api-image local. - Ansible for the installer (Ubuntu), on the machine that runs
k7 install:
- Python 3.10+ on the client for the SDK
Tested setup: Hetzner Robot dedicated, Ubuntu 24.04, with a spare raw NVMe for the kfd thin-pool. Dual-NVMe boxes (no third drive): put Ubuntu on one disk (SWRAID 0) and leave the other raw — see Hetzner node setup. Do not pin --disk /dev/nvme1n1: NVMe names swap across reboots; the playbook auto-detects the empty non-root disk.
Install the CLI#
The Launchpad PPA publishes 0.5.0 (k7 -V after install). PyPI k7-sdk is the same version.
The same package is on the GitHub release if you prefer not to add the PPA:
Install K7 on your node(s)#
k7 install runs from any directory — no clone, no Docker. It deploys the signed ghcr.io/katakate/k7-api image at the digest recorded in the release’s images.lock.yaml, and verifies the cosign signature before use.
Two flags are required (no silent defaults):
--backend:kfdneeds a spare raw disk;kqluses Longhorn on the OS disk;k7dis the warm-fork daemon;k7d-fcadds jailed Firecracker v1.16.2;noneis control-plane only. The playbook pins k7d 0.7.0.--api-mode:production(every API key belongs to a tenant, HTTPS only, metering mandatory) ordevelopment(unscoped keys keep working, remote install allowed). Documented in Hardening.
That installs and wires up Kubernetes (K3s v1.36.5+k3s1, override with --k3s-version), Cilium, Kata, Firecracker + Jailer + thin-pool (kfd), QEMU + Longhorn (kql), and the k7d daemon + RuntimeClass k7 / k7-fc (k7d, k7d-fc). It also deploys the k7-api (2 replicas) over HTTPS with a cluster CA, the non-privileged k7-agent DaemonSet, Prometheus metrics and the metering spool. Pass -v for verbose output. Two-node / HA inventories: Multi-node clusters; install-time knobs (--api-allow-cidr, --api-hostname, --oidc-*, --dns-upstream, --metering-*, --hubble): CLI reference. To install a k7d tarball you built yourself instead of GitHub v0.7.0, pass --k7d-artifact /path/to/k7d-v0.9.0-x86_64-linux.tar.gz.
Already running Kubernetes (RKE2, kubeadm, EKS)? The same stack ships as a Helm chart (deploy/helm/k7) that never installs Kubernetes, the CNI or the CSI driver: see Helm chart.

You should see “Installation completed successfully!” when done. Add -v for verbose output.
The API and managing keys#
k7 install deploys the K7 API automatically as a k7-api Deployment in
kube-system. K3s keeps it running and reschedules it on failure — there’s
no separate “start” step. If you want a CLI-only install with no API
deployed, pass --no-api to k7 install.
Check API status#
On a cluster node (needs kubectl / k3s kubectl):
From a laptop after k7 config set, the same command probes GET /health on the configured URL instead of crashing. Replica counts still need kubectl on the node.
Get the endpoint#
On a node this is /etc/k7/api_endpoint. From a laptop it prints the URL you configured.
Trust the cluster CA from your laptop#
The default install serves the API over HTTPS with a certificate signed by a cluster CA the playbook minted (Let’s Encrypt cannot issue for a bare IP). Copy the CA off the node once and point the CLI at it:
If you installed with --api-hostname k7.example.com, the certificate is publicly trusted and api.ca is unnecessary. On the node itself the CLI finds /etc/k7/api_endpoint and /etc/k7/tls/ca.crt automatically; you still have to k7 config set api.key with the token generate-api-key printed.
Generate an API key#
Every key has a role (--role is required): read-only and user belong to a tenant, operator and admin are cluster-wide. In --api-mode development a user key without --tenant keeps the pre-0.5 “unscoped” behaviour; in production every read-only/user key needs a tenant.
A tenant key cannot list or mutate another tenant’s namespaces and cannot run all-namespaces operations. Details and quotas: Tenants, roles and OIDC.
Save the printed key. k7 generate-api-key stores only a hash in the kube-system/k7-api-keys Secret — the raw token is shown once and is not auto-loaded on the node. Key commands edit that Secret through kubectl, so run them on a server node (or add --api to go through k7-api with an admin credential). Point the CLI at it (laptop or node):
Humans can skip keys altogether: with k7 install --oidc-issuer … --oidc-client-id …, k7 login signs in through the IdP (device flow by default, --browser for Authorization Code + PKCE) and stores a short-lived token; k7 whoami shows the resolved role.

Temporarily disable / re-enable the API#
- API keys live in the
kube-system/k7-api-keysSecret (hashes only); every API replica picks up a change within 5 seconds. Keys created before 0.5.0 in/etc/k7/api_keys.jsonwere migrated byk7 install(k7 api keys migrate) and keep working until they expire. Authentication accepts theX-API-Keyheader orAuthorization: Bearer <token>(API key or OIDC JWT). - The previous top-level commands
k7 start-api/k7 stop-api/k7 api-status/k7 get-api-endpointare hidden deprecated aliases that forward tok7 api …with a warning.
Create your first sandbox via CLI#
Example k7.yaml:
Do not use cpu: 100m / memory: 128Mi. Kata Firecracker refuses hypervisor memory below 256Mi (io.katacontainers.config.hypervisor.default_memory) and the pod stays ContainerCreating until create times out. Use at least 1Gi (or omit limits).
Create a sandbox#
CLI k7 create with no --egress / --egress-open blocks all egress. An API/YAML request that omits egress_whitelist leaves egress open. Use --egress-open or omit the field in YAML when you want the internet.

Shell into your sandbox#

List sandboxes#

Delete a sandbox#
Delete all sandboxes#
Prerequisites for the SDK#
Always pass the cluster CA (./k7-ca.crt from your laptop, or /etc/k7/tls/ca.crt on the node). k7 api status prints an SDK snippet that already includes verify_ssl.
Create your first sandbox via Python SDK#
Install the SDK on your client (laptop), not necessarily on the cluster node:
A freshly installed Ubuntu node does not include python3-venv. If you run the SDK on the node: sudo apt install -y python3-venv python3-pip, then python3 -m venv ~/k7sdk && ~/k7sdk/bin/pip install k7-sdk==0.5.0. pip install --break-system-packages k7-sdk==0.5.0 also works on Ubuntu 24.04.
Use the synchronous client:
Async variant:
Next steps#
- Explore the CLI guide
- Explore the Python SDK guide
- Run Docker inside a sandbox
- Integrate with the REST API
