Skip to content

Container Runtimes

terok supports two OCI runtimes:

  • crun (default) — OS-level containers via crun.
  • krun (experimental) — KVM microVM isolation via libkrun.
crun krun
Isolation namespaces + cgroups + SELinux KVM hypervisor
Status in terok stable, default experimental
Needs KVM (/dev/kvm) no yes

Optional dependencies for krun

Package Purpose Install (Fedora)
crun-krun Adds libkrun and points podman's --runtime krun at the right binary dnf install crun-krun (or rpm-ostree install on Silverblue, then reboot)

Check ls -l /dev/kvm — if it's world-rw (crw-rw-rw-, the Fedora default) you're done; if it's crw-rw---- root:kvm (Debian/Ubuntu default), add your user to the owning group.

Enabling krun

Two steps:

1. Flip the global flag in ~/.config/terok/config.yml:

experimental: true

2. Set the runtime — either globally in ~/.config/terok/config.yml:

run:
  runtime: krun

…or per project in project.yml:

run:
  runtime: krun
  memory: 4g     # optional, podman --memory format
  cpus: 4        # optional, podman --cpus format

Project-level settings override the global default. Without experimental: true set globally, any krun selection fails fast at startup with a pointer at the opt-in — a typo in project.yml can't silently switch isolation backends.

Resource limits

run.memory and run.cpus apply to both runtimes.

Under crun they ride on podman's --memory / --cpus flags and become cgroup quotas: the scheduler and OOM killer enforce them, but btop / nproc / /proc/meminfo inside the container still report host values (check /sys/fs/cgroup/{cpu,memory}.max to verify).

Under krun the asymmetry surfaces:

  • run.memory works through podman's --memory because crun-krun reads the OCI memory limit as a fallback when sizing the microVM, so free reports the right number.
  • run.cpus does not size the VM by itself — --cpus only sets the cgroup CFS quota, which throttles the VM host-side but doesn't change its vCPU count. terok additionally emits the krun.cpus OCI annotation (the documented knob crun-krun reads, rounded up from run.cpus and capped at 16), so the guest sees the matching vCPU count.

Switching runtime via env var

For one-off testing without editing any file:

TEROK_RUNTIME=krun terok task start <project>

Accepted values: crun, krun, null (in-memory stub for tests). Unset means "fall through to project/global config".

krun runner behaviour

The container's PID 1 runs as root, and run.nested_containers: true is rejected at launch.

Login

terok login <project> <task> works for both runtimes. Under crun it uses podman exec. Under krun it uses ssh to an in-container sshd reached via a per-task loopback port forward. Two users can log in with the same key:

  • dev — default; use this for agents that refuse uid 0.
  • root — log in as root.

Under krun, each running task holds one loopback TCP port for sshd, visible to every local user on the box.

Image build

One L0/L1/L2 chain serves both runtimes — toggling run.runtime doesn't trigger a rebuild.