
vpod v0.7.1
Leichtgewichtige, sichere Linux-Sandboxes für nicht vertrauenswürdige Prozesse. Läuft im Browser und auf dem Server.
Vpod
Was ist ein vpod?
Ein vpod ist eine leichtgewichtige, portable Sandbox, die einem nicht vertrauenswürdigen Prozess eine sofort einsatzbereite Linux-Umgebung bietet. Sie nutzt eine RISC‑V-Architektur und läuft vollständig in WebAssembly.
- Schneller Start: Start in unter einer Sekunde.
- Portabel: Läuft überall ohne jegliche Einrichtung.
- Isoliert: Der gesamte Ausführungszustand bleibt innerhalb der WASM-Sandboxes.
So funktioniert es
Ein vpod führt ein vollständiges RISC‑V-System (RV64GC, einzelne vCPU) aus, das zu WebAssembly kompiliert wurde. Darin bootet ein echter Linux-Kernel mit einem echten Userspace, sodass sich Shells, Werkzeuge und Dienste genau so verhalten wie auf echter Hardware.
Snapshots. Anstatt Linux von Grund auf zu booten, stellt ein vpod einen Snapshot wieder her: einen gespeicherten Maschinenzustand (CPU-Register, RAM, Dateisystem), der direkt nach dem Boot erfasst wurde. Die Wiederherstellung dauert deutlich unter einer Sekunde. Suspend funktioniert umgekehrt auf die gleiche Weise – es werden nur veränderte Speicherseiten zurück auf die Festplatte geschrieben. So kannst du eine Sandbox pausieren und später, sogar aus einem anderen Prozess heraus, fortsetzen.
Ahead-of-time-Übersetzung. Reine Befehls-für-Befehls-Emulation ist langsam, und WebAssembly schließt einen JIT zur Laufzeit aus. Daher werden zur Snapshot-Build-Zeit die heißesten Gast-Codepfade von RISC‑V in nativen Code übersetzt, der direkt in das WASM-Modul einkompiliert wird. Zur Laufzeit verzweigt der Emulator in diese übersetzten Blöcke, wenn der Gast-Code passt, und fällt andernfalls auf den Interpreter zurück. Das bringt bei CPU-gebundener Arbeit etwa 5x, ohne die Isolierung zu beeinträchtigen: Übersetzter Code durchläuft dieselben MMU- und Speicherprüfungen wie interpretierter Code.
Die WASI-Grenze. Die WASM-Komponente kommuniziert ausschließlich über WASI 0.2 mit dem Host. Der Gast sieht niemals Host-Dateideskriptoren, Sockets oder Speicher: Der Dateisystemzugriff erfolgt über explizit gemountete Verzeichnisse, und die Netzwerkkommunikation läuft über einen Netzwerk-Stack im Benutzermodus innerhalb der Komponente, der den Host nur um einfache ausgehende Sockets bittet. Alles andere (Gast-Kernel, Prozesse, Speicher) lebt im linearen Speicher des WASM und stirbt mit ihm.
RV64GC-Spezifikation
G (Allzweck-Erweiterungen)
- I: Basis-Befehlssatz für 64-Bit-Ganzzahlen.
- M: Hardware-Multiplikation und -Division, nützlich für Hashing und Kryptografie.
- A: Atomare Operationen für threadsichere Programme.
- F/D: Gleitkommazahlen mit einfacher und doppelter Genauigkeit, geeignet für wissenschaftliches Rechnen und ML-Inferenz.
C (Komprimierte Befehle) Reduziert die Codegröße um 30 % und verbessert so die Befehlsabrufgeschwindigkeit und die Speichereffizienz. Das ist wichtig, wenn ein vollständiger Linux-Userspace in unserer speicherbegrenzten WASM-Umgebung läuft.
[!NOTE] Die V (Vektor)-Erweiterung ist nicht implementiert. RVV-Befehle würden als emuliertes RISC-V ausgeführt; es gibt kein SIMD-Durchreichen an die Host-CPU. Das Hinzufügen von V würde den Emulationsaufwand erhöhen, ohne einen Leistungsvorteil für vektorisierte Arbeitslasten zu bringen.
Erste Schritte
Python-SDK
pip install vpod
from vpod import Sandbox
# Run a command
sandbox = Sandbox.create()
result = sandbox.commands.run("whoami")
print(result.stdout) # root
sandbox.close()
# Persistent session — state preserved across calls
with Sandbox.create() as sandbox:
sandbox.commands.run("export API_KEY=secret")
result = sandbox.commands.run("echo $API_KEY")
print(result.stdout) # secret
# Python REPL — variables persist
with Sandbox.create() as sandbox:
sandbox.code.run("import requests")
sandbox.code.run("data = [1, 2, 3]")
result = sandbox.code.run("print(sum(data))")
print(result.text) # 6
[!IMPORTANT] Der erste Aufruf von
Sandbox.create()lädt den Standard-Snapshot (alpine) herunter und speichert ihn lokal zwischen, falls er nicht bereits vorhanden ist.
CLI
curl -fsSL https://install.vpod.sh | sh
Oder Installation über PowerShell (Windows)
irm https://install.vpod.sh | iex
# Pull a snapshot
vpod pull alpine:latest
# Start an interactive shell
vpod
Dokumentation
Besuche die Vpod-Dokumentation.
Einschränkungen
- Emulationsaufwand: Es gibt keine Hardware-Virtualisierung in WebAssembly, daher wird der gesamte Gast-Code emuliert. Der Aufwand hängt vollständig von der Arbeitslast ab: I/O-gebundene und netzwerkgebundene Arbeit läuft nahezu mit nativer Geschwindigkeit, während stark CPU-gebundene Arbeit selbst mit AOT-Übersetzung deutlich langsamer läuft. Wenn deine Arbeitslast hauptsächlich aus „Tool ausführen, Datei lesen, API aufrufen“ besteht, wirst du es nicht bemerken.
- Kein GPU-Zugriff: CUDA, Metal und Hardware-ML-Beschleuniger sind nicht verfügbar. Unterstützung könnte in Zukunft mit wasi-nn hinzugefügt werden.
Mitwirken
Beiträge sind willkommen, von Fehlerberichten bis hin zur Unterstützung neuer Geräte. Eröffne ein Issue, um substanzielle Änderungen zu besprechen, bevor du sie umsetzt.
Voraussetzungen
- Rust (aktuelles Stable) mit dem
wasm32-wasip2-Ziel:rustup target add wasm32-wasip2 - Python 3.10+ für das SDK
- Zig (0.16) und bsdtar, nur benötigt, wenn du Snapshots selbst erstellst
Entwicklungseinrichtung
# One-time: generate the AOT stub (a fresh clone has no translated blocks)
./scripts/aot-stub.sh
# Build the WASM component (library + CLI)
./scripts/build-wasm.sh
# Install the host CLI
cargo install --path crates/vpod
# Install the Python SDK in dev mode
pip install -e "sdks/python[dev]"
Tests ausführen
CI führt diese bei jedem PR aus, daher solltest du sie vor dem Pushen ausführen:
cargo fmt --all -- --check # formatting
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all # Rust tests
# Python SDK integration tests (needs the WASM library in place)
cp target/wasm32-wasip2/release/vpod_wasi_lib.wasm sdks/python/vpod/
pytest sdks/python/tests/ -v -m integration
Snapshots erstellen
Das Projekt verwendet vorgefertigte Alpine-Snapshots von registry.vpod.sh, daher ist das normalerweise nicht nötig. Um einen lokal zu erstellen:
./scripts/build-default-snapshot.sh # dist/alpine-3.23.0-256mb.snap
./scripts/build-data-snapshot.sh # 512 MB variant with numpy/pandas/scipy
[!IMPORTANT] Um einen lokal erstellten Snapshot zu verwenden, kommentiere die Zeilen in
resolve_snapshot()incrates/vpod/src/main.rsaus.
Snapshot-Builds können auch den AOT-Durchlauf ausführen (scripts/aot-snapshot.sh <snapshot>), der eine repräsentative Arbeitslast verfolgt, die heißen Blöcke übersetzt und den Emulator mit diesen einkompiliert neu erstellt. Das dauert eine Weile; der Stub von aot-stub.sh ist für die tägliche Entwicklung völlig ausreichend – alles funktioniert gleich, nur langsamer.
Pull-Requests
- Halte PRs fokussiert: eine Änderung pro PR.
fmt,clippyund die Testsuite müssen bestehen (CI erzwingt alle drei).- Wenn du die Ausführungs- oder Speicherpfade des Emulators änderst, beschreibe, wie du die Korrektheit validiert hast (mindestens die Testsuite; bei subtilen Änderungen sind ein Boot plus eine reale Arbeitslast im Gast ein guter Plausibilitätscheck).
Lizenz
Dieses Projekt ist unter der Apache-Lizenz 2.0 lizenziert. Einzelheiten findest du in der Datei LICENSE.
