Hyperlight Unikraft
Hyperlight Unikraft runs Unikraft unikernels on Hyperlight, enabling Linux applications written in Python, Node.js, Go, Rust, C, and C++ to execute inside hardware-isolated micro virtual machines.
It provides a CLI host that loads a Unikraft kernel and optional initrd, passes application arguments into the guest, and captures console output through Hyperlight. The project also includes ready-to-use example configurations for building and running common application runtimes.
Key features include:
- Unikernel execution — Run Linux application binaries inside Unikraft guests on Hyperlight
- Thin, opt-in host surface — Guests have no host filesystem, network, or host functions by default;
--mount,--net, and--enable-toolsopt in through a single__dispatchJSON-RPC bridge - Broad language support — Use examples for Python, Node.js, Go, Rust, C, C++, and more
- Generic command line — Pass arguments to any application with
-- arg1 arg2 ... - Fast startup — Use Hyperlight’s lightweight VMM for low-latency micro virtual machine startup
- Host filesystem sandboxing — Preopen host directories and expose them to guest applications with path isolation
From commandline:
# Install pyhlcargo install --git https://github.com/hyperlight-dev/hyperlight-unikraft \ hyperlight-unikraft-host --bin pyhl
pyhl setup --from examples/python-agent-driverpyhl run -c 'import pandas as pd; print(pd.DataFrame({"x":[1,2,3]}).sum().to_dict())'As a library:
fn main() -> anyhow::Result<()> { let code = std::env::args() .nth(1) .unwrap_or_else(|| r#"print("hello from the pyhl library API")"#.to_string());
let home = std::env::var("PYHL_HOME") .map(std::path::PathBuf::from) .unwrap_or_else(|_| Path::new(".pyhl").to_path_buf());
// Default: no mounts. Add `Preopen::new(host, guest)` entries to // expose host directories via the guest's hostfs. let mounts: &[Preopen] = &[];
let mut rt = pyhl::Runtime::new(&home, mounts, None, None)?;
eprintln!("-- first run (hermetic from loaded snapshot) --"); let t1 = rt.run_code(&code)?; eprintln!("restore={:.1}ms call={:.1}ms", t1.restore_ms, t1.call_ms);
eprintln!("-- second run (restores to the same snapshot) --"); let t2 = rt.run_code(&code)?; eprintln!("restore={:.1}ms call={:.1}ms", t2.restore_ms, t2.call_ms);
Ok(())}