
Rootless-Container-Runtime und Sandbox, die kernel-erzwungene OCI-Images in Millisekunden ohne Daemon startet und Ressourcenprofile, Seccomp-Allowlists sowie Compose-Unterstützung für nicht vertrauenswürdigen und KI-generierten Code bietet.
kern: Eine schnelle, rootless Sandbox- und virtuelle Ressourcen-Runtime für beliebige Workloads, einschließlich nicht vertrauenswürdigem und KI-generiertem Code.
Ein echter, kernel-erzwungener Container in ~3,5 ms, aus einer einzigen 1,52-MB-Binärdatei ohne Daemon.
0 RAM im Ruhezustand · kein Daemon, kein Socket, nichts zu starten · eine statische Binärdatei, libc als einzige Rust-Abhängigkeit
# install the release binary (static, 1.52 MB, checksum-verified by the script)
curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh
# a throwaway shell in a real OCI image: rootless, kernel-enforced, a few ms
kern box dev --image alpine -it -- sh
Kein natives Windows: WSL2 verwenden. Installation.
Eine Binärdatei, die Ressourcen verwaltet, von denen die Isolation die erste ist. Deshalb gibt es keine einzelne Zeile für kern in einer Vergleichstabelle: Es ist zugleich Container-Runtime, Sandbox, Ressourcen-Slicer und Stack-Runner, in 1,52 MB ohne Daemon.
pull, build aus einem Dockerfile, commit, push, save/load. Eine Box aus einem Image startet in ~3,5 ms.pivot_root eingehängt wird, eine seccomp-Allowlist (Deny-by-Default) und cgroup-v2-Limits. Ein einziges Flag, --security-profile untrusted, ist das gesamte gehärtete Bündel.vcpu:), Speicher, Disk (vdisk:) und Geräte (vgpio:), einmal in einer kern.toml deklariert und per Name zugewiesen. kern run wendet dieselben Caps auf einen Prozess auf dem Host an, ganz ohne Sandbox. Sein gesamter Rust-Abhängigkeitsbaum ist libc: JSON- und OCI-Manifeste werden von Hand geparst, und pull greift auf das bereits auf dem Rechner vorhandene curl und tar zurück, statt einen TLS-Stack einzubinden. (1,52 MB ist der größenoptimierte Release-Build; ein einfaches cargo install aus dem Quellcode ergibt 1,91 MB.)
Kein Hypervisor. Die Grenze ist der Linux-Kernel, daher ist ein Kernel-Privilege-Escalation-Bug ein Escape. Docker und Podman teilen diese Bedingung, weshalb es gVisor und Firecracker gibt.
Zusammen mit dem Slogan gelesen ist das eine Zeile, die von beiden Seiten gesehen werden kann: Nicht vertrauenswürdiger und KI-generierter Code ist das, wofür kern DA ist, weil du dich entscheidest, ihn auszuführen und den Schadensradius zu verantworten (Agent-Tool-Aufrufe, CI-Jobs, Build-Schritte, Code-Zellen). Wofür es nicht da ist, ist feindlicher Code von Fremden, Multi-Tenant, auf einem Kernel, von dem du andere Mandanten bedienst. kern startet immer rootless, während das bei Docker optional ist.
Nicht frei vom Userns-Kompromiss. Seine Isolation basiert auf einem unprivilegierten User-Namespace, einer ergiebigen Quelle für Kernel-LPE-Bugs. SECURITY.md stellt das vor jede Behauptung.
Keine Mauer um das, was du einhängst. -v $HOME:/host gibt der Box dein Home-Verzeichnis: Ein Mount ist eine Vertrauensentscheidung, die du triffst, keine Grenze, die kern durchsetzt. --net host und --privileged sind Opt-out per Name. (Der eine Pfad, den kern sich weigert zu binden, ist seine eigene Runtime-Registry.)
Keine Neuimplementierung der Docker Engine. Es spricht DOCKERs Formate, nicht seine API: keine Overlay-Netzwerke, keine Plugins, kein Swarm. Matrix: docs/DOCKER-COMPAT.md.
Keine Kubernetes-Runtime. Kein CRI. Verwende containerd oder CRI-O.
Keine GPU-Slices. Auf der Roadmap, ohne GPU-Code in dieser Ausgabe, also gibt es hier noch nichts zu vertrauen oder anzugreifen.
Was es noch nicht weiß oder noch nicht kann, steht in OPEN_ITEMS.md, statt dass du es selbst herausfinden musst.
kern benötigt einen Linux-Kernel mit unprivilegierten User-Namespaces und cgroup v2. Es läuft auf Linux, WSL2 und ARM-Boards (Raspberry Pi · Jetson · Arduino UNO Q); es gibt kein natives Windows-Build, verwende WSL2 (kern liefert ein vorgefertigtes WSL-Rootfs mit).
Der schnellste Weg ist das Release-Binary: eine statische Datei, keine Toolchain, und das Skript verifiziert dessen SHA256, bevor es sie installiert.
curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh
Es wählt für dich x86_64 oder aarch64, installiert nach ~/.local/bin (/usr/local/bin als Root oder KERN_INSTALL_DIR) und weigert sich, einen Download zu installieren, dessen Prüfsumme nicht übereinstimmt. Die manuelle Überprüfung geht in zwei Zeilen:
curl -fsSLO https://github.com/getkern/kern/releases/latest/download/kern-x86_64-unknown-linux-musl.tar.gz{,.sha256}
sha256sum -c kern-x86_64-unknown-linux-musl.tar.gz.sha256 && tar xzf kern-x86_64-unknown-linux-musl.tar.gz
Aus dem Quellcode ist der andere Weg, und der gesamte Abhängigkeitsbaum ist eine einzige Crate (libc), also kurz: Klonen, Bauen und Installieren dauerte auf einem Desktop 36 s (i7-14700KF), auf einem kleinen ARM-Board länger.
# if you do not have Rust yet
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install --git https://github.com/getkern/kern getkern --locked
Das legt kern in ~/.cargo/bin, das rustup zu deinem PATH hinzufügt (öffne eine neue Shell oder source "$HOME/.cargo/env", wenn kern nicht gefunden wird).
Das Release enthält außerdem ein aarch64-Binary, einen Windows-.exe-Shim und ein vorgefertigtes WSL-Rootfs, jeweils mit eigener .sha256; der Tag ist GPG-signiert und unabhängig zeitgestempelt (provenance/).
kern doctor sagt dir, ob Boxen hier laufen, bevor du es versuchst. Boards, WSL2 und die ausführliche Fassung: docs/INSTALL.md. Häufige Fragen (Docker, bubblewrap, youki, E2B, Windows, das Bedrohungsmodell): docs/FAQ.md.
kern box dev --image alpine -it -- sh # a throwaway shell in a real OCI image
kern run --memory 256M --cpus 0.5 -- ./crunch # cap a process, no sandbox
kern box svc --image nginx:alpine -d -p 8080:80 \ # a service: published, restarted, health-checked
--restart --health-cmd 'wget -qO- localhost:80' -- nginx -g 'daemon off;'
kern ps # what is running, with PORTS and HEALTH
kern exec svc -it -- sh # shell into it
kern stop svc # its signal, its grace, then the code it exited with
kern top # live TUI: boxes, CPU/RAM, profiles, volumes
kern compose stack.toml up # a multi-box stack (examples/) or a compose.yml
kern compose stack.toml down # and take it down again
Nicht vertrauenswürdiger Code, ein Flag für das gesamte Bündel:
kern box job --image python:3.12-slim --security-profile untrusted --memory 256m \
-v ./job:/w -- python3 /w/x.py
--security-profile untrusted ist die seccomp-Allowlist + --cap-drop ALL + --read-only in einem Opt-in-Flag (schreibe sie bei Bedarf aus); füge --require-limits hinzu, um den Start zu verweigern, wenn die Speicher-/Pids-Caps nicht tatsächlich durchgesetzt werden. Kein Netzwerk, außer du fragst danach, gefährliche Capabilities werden entfernt, seccomp ist immer an. Neunzig ausführbare Beispiele, jedes mit einer einzigen Aufgabe: examples/.
Jede Lese-Operation antwortet auch in JSON, sodass nichts eine Tabelle parsen muss:
kern ps --json | jq '.[] | select(.health == "unhealthy") | .name'
kern volume ls --json # ps · images · stats · inspect · builds · pod ls · config list · diff
kern spricht docker-compose.yml. Zeig ihm den Stack, den du bereits hast, und kern compose up führt ihn ohne Daemon und ohne Docker Desktop aus, genauso unter Linux, WSL2 und ARM-Boards.
# compose.yaml - a real stack, unchanged
services:
db:
image: postgres:alpine
environment: { POSTGRES_PASSWORD: secret, POSTGRES_DB: app }
web:
image: adminer
ports: ["8080:8080"]
depends_on: [db]
kern compose compose.yaml up
Beide offiziellen Images starten, web erreicht db über den Dienstnamen, und der Port wird auf dem Host veröffentlicht. Warm (Images gecacht) antwortet die Web-Schicht in ~0,3 s, und der Stack kostet nur das, was postgres und adminer tatsächlich verbrauchen (~66 MB hier), mit null Daemon obendrauf, während Docker Desktop schon vor deinem ersten Container eine Hintergrund-VM ist.
Offizielle Images, die auf einen Nicht-Root-Benutzer wechseln (postgres, redis, ...), benötigen uidmap und eine /etc/subuid-Zeile, und ausgehende Image-Pulls benötigen pasta; beides ist auf einer Dev-Box ein einziges apt install, und kern doctor nennt beides, wenn es fehlt. Das ist die lokale Entwicklungs-Schleife, kein Produktions-Orchestrator: kein Swarm, keine Overlay-Netzwerke.
Führe Agent- oder LLM-generierten Code aus deinem eigenen Programm mit kern-sandbox aus, einem schlanken, dependencies-freien Wrapper um die kern-Binärdatei. Jeder Aufruf läuft in einer frischen, isolierten Box: Netzwerk aus, Speicher- und PID-Caps, Capabilities entfernt, Ausgabe begrenzt und ein Timeout, das das Binding selbst durchsetzt.
pip install kern-sandbox # PyPI · needs the `kern` binary above, on PATH or $KERN_BIN
npm install kern-sandbox # npm · same
from kern_sandbox import run_code
r = run_code("import platform; print(platform.python_version())")
print(r.stdout) # ran in a fresh box; a timeout / OOM / blocked escape is data on r.fault
Sandbox behält einen Workspace über Aufrufe hinweg, und ein warmes kernel() behält einen Interpreter für Sub-Millisekunden-Zellen (schwächere Isolation, bewusst gewählt).display() und matplotlib-Abbildungen werden erfasst zurückgegeben, wie eine Notebook-Zelle.kern-mcp): einen dependencies-freien stdio-Server, der Claude Desktop, Cursor oder jedem MCP-Client einen lokalen Code-Interpreter bietet. Weise den Client darauf hin:{ "mcpServers": { "kern": { "command": "kern-mcp" } } }
Tools: run_code (python/bash/node), write_file, read_file, list_files. Jeder Aufruf ist eine frische Box ohne Netzwerk; Dateien bleiben über Aufrufe hinweg in einem Workspace auf der Platte erhalten. Setup-Befehl, Image und die anderen Optionen: bindings/python/README.md.
Vollständige API, Python und Node: bindings/python/README.md · bindings/node/README.md.
Eine Slice wird einmal in ~/.config/kern/kern.toml deklariert und per Name angehängt, an eine Sandbox-Box oder einen nackten Prozess, mit demselben Token.
Drei Arten: vcpu: (CPU und Speicher), vdisk: (eine Scratch-Disk mit Größenlimit) und vgpio: (Device-Knoten). Zwei davon und die Anker, aus denen sie geschnitten werden:
[[cpu]] # the host budget a slice is carved from
id = "cpu:0"
cores = 8.0
[[vcpu]] # 1.5 cores and 512 MiB -> attach as vcpu:heavy
name = "heavy"
backend = "cpu:0"
cpus = 1.5
memory = "512m"
[[gpio]] # a controller anchor
id = "gpio:0"
[[vgpio]] # exactly one device node -> attach as vgpio:sensor
name = "sensor"
backend = "gpio:0"
i2c = ["/dev/i2c-1"]
kern validate ~/.config/kern/kern.toml # check it before anything runs
kern box train --image alpine vcpu:heavy vdisk:scratch -- ./train.sh
kern run vcpu:heavy -- ./train.sh # the same slice, no sandbox
kern box iot --image alpine vgpio:sensor -- ls /dev
Profile lassen sich kombinieren: Mehrere können an einer Box hängen, und ein explizites Flag schlägt den eigenen Wert eines Profils. Jeder Schlüssel wird wie sein CLI-Flag geschrieben, also cpus ist --cpus und memory ist --memory. Ein Backend, das keinen deklarierten Pool nennt, wird beim Lesen der Konfiguration abgelehnt, nicht wenn die Box läuft. docs/RESOURCES.md enthält das Schema Feld für Feld.
Ein vdisk: ist ein RAM-gestütztes tmpfs, wenn kern rootless läuft, egal was sein Backend sagt, und ein ext4-on-loop-Image mit einem echten Kontingent, wenn es privilegiert läuft. kern sagt pro Profil, welches du bekommen hast, statt dich vermuten zu lassen, und das Größenlimit wird in beiden Fällen durchgesetzt.
vgpio: ist Chip-granular, nicht pro Leitung. Wenn du pins anforderst, wird das gesamte /dev/gpiochipN gebunden, und dieses Character-Device legt jede Leitung dieses Controllers offen. pins = [17] schränkt die Box nicht auf Leitung 17 ein: Der Kernel hat keine Per-Leitung-Mount-Grenze, also ist die Pin-Liste kooperative Metadaten statt einer Grenze. Einen Device-Node zu benennen, wie es i2c oben tut, gewährt genau diesen Node und sonst nichts.
Intel i7-14700KF, Linux 7.0.0, das Release-Binary, ein Skript, das du selbst ausführen kannst: python3 examples/benchmark.py. Deine Werte werden sich je nach CPU, Kernel und Dateisystem unterscheiden.
Dreitausend auf einmal brauchen ~2,2 s, und eine laufende Box kostet ~0,3 MB Speicher.
Zwei ehrliche Anmerkungen. Niemand gewinnt die Einzelschuss-Latenz eindeutig: Die Untergrenze für unshare + exec liegt bei 1 bis 2 ms, also liegt die gesamte Spitzengruppe im eigenen Rauschen, und bubblewrap ist ein Launcher ohne Images, Caps oder Lebenszyklus. Der Abstand, der etwas bedeutet, ist zu den Engines – zwei Größenordnungen darüber.
Methode, Aufschlüsselung pro Phase, Zahlen für Boards und alle Einschränkungen: BENCHMARKS.md.
Namespaces, ein pivot_root, 16 gefährliche Capabilities, die vor exec entfernt werden, eine standardmäßig immer aktive seccomp-Allowlist (mobys eigener Standardfilter minus kerns 35 Escape-Syscalls, die weiterhin hart gekillt werden; ein Syscall außerhalb des geprüften Satzes gibt ENOSYS zurück, und die breitere Denylist ist der Opt-out über KERN_SECCOMP=denylist), cgroup-v2-Limits (--require-limits verweigert den Start, wenn sie nicht greifen) und ein /dev mit Deny-by-Default. Wo eine Grenze kooperativ statt kernel-erzwungen ist, sagt SECURITY.md das und nennt den Bypass.
Du musst es nicht einfach glauben: pentest/ enthält vier adversariale Test-Suites, die diese Grenzen gegen den Kernel prüfen und nicht gegen kerns eigene Berichterstattung, und sie laufen ohne Registry-Konto oder Netzwerk.
sh pentest/run-with-local-registry.sh ./target/release/kern pentest/pentest-ports.sh
Melde eine Schwachstelle vertraulich über GitHub Security Advisories oder [email protected].
Der Kern ist fertig. Alles oben funktioniert heute: 840 Rust-, 78 Python- und 61 Node-Tests, clippy-sauber, cargo-deny-sauber, auf echter Hardware: Linux, WSL2, Raspberry Pi 5, Jetson Orin Nano, Arduino UNO Q. v0.7.0 ist die erste veröffentlichte Version. Die CLI- und Konfigurationsoberfläche kann sich noch ändern, immer ausgewiesen in CHANGELOG.md.
Issues und Pull-Requests sind willkommen. CONTRIBUTING.md enthält den Workflow und die Gates; Beiträge sind durch die CLA abgedeckt.
Alex, @realexhub. Commits stammen von @getkerndev, der Commit-Identität des Projekts.
Die Commits sind nicht signiert; der Release-TAG ist es. Das ist es, was du verifizieren solltest: git verify-tag v0.7.0 gegen den Schlüssel in provenance/, dessen Fingerabdruck in SECURITY.md steht.
Apache-2.0. Siehe LICENSE und TRADEMARK.md.
kern compose <file> up akzeptiert eine kern-compose.toml ([box.NAME]-Tabellen, mit den Ressourcenprofilen von oben) oder das bereits vorhandene docker-compose.yml, so wie es geschrieben ist. Ein Stack zu einem Pod, Dienste erreichen einander per Name.ps, logs, exec, stats, inspect, wait, top (eine Live-TUI), doctor, plus ein Python- und Node-SDK und einen MCP-Server für Agents.| kern | Docker | Podman |
|---|
| Daemon | nein | ja (dockerd + containerd) | nein |
| Rootless | ja, immer | Opt-in | ja |
| Kaltstart, nackte Box | ~2,3 ms | ~297 ms | ~293 ms |
| Kaltstart aus einem OCI-Image | ~3,5 ms | ~297 ms | ~293 ms |
| Dienst stoppen (init behandelt SIGTERM) | ~1,9 ms | ~310 ms | ~380 ms |
| Residenter Speicher, nichts läuft | 0 | 154 bis 160 MB | 0 |
| Footprint | eine 1,52-MB-Binärdatei | Daemon-Stack | Multi-Binary-Installation |
| OCI-Images, pull / build / push | ja | ja | ja |
docker-compose.yml | ja, unverändert gelesen | ja | teilweise |
| Overlay-Netzwerke, Swarm, CRI | nein | ja | teilweise |
| GPU | auf der Roadmap | ja | ja |
| kern | bubblewrap | runc | podman | docker |
|---|
| Kaltstart (nackte Box) | ~2,3 ms | ~2,3 ms | ~18,6 ms | ~293 ms | ~297 ms |
| 200 Boxen parallel | ~0,11 s | ~0,16 s | ~0,35 s | ~44,8 s | ~16,2 s |
| docs/INSTALL.md | Installation auf Linux, WSL2 und ARM-Boards, aus dem Quellcode |
| docs/DOCKER-COMPAT.md | Was von Docker funktioniert, was nicht und wo es sich unterscheidet |
| docs/RESOURCES.md · docs/CONFIG.md · docs/STORAGE.md · docs/EGRESS.md | das Zwei-Verben-Modell, das kern.toml-Schema, Volumes und Egress |
| docs/THREAT_MODEL.md · SECURITY.md · OPEN_ITEMS.md | das Bedrohungsmodell (strukturiert, dann pro Mechanismus) und die bekannten Lücken |
| BENCHMARKS.md · EDGE.md | Messwerte und der Betrieb auf einem Pi, Jetson oder UNO Q |
| examples/ · blog/ | neunzig ausführbare Skripte und längere Artikel |
| bindings/python/README.md · bindings/node/README.md | das kern-sandbox-SDK: kern in Python oder Node einbetten |