virtx
virtx lets you run tasks in disposable Linux VMs from your own code.
It's useful for jobs with heavy dependencies that you'd rather not install on your own machine. Whatever they install or change is gone when the VM shuts down.
No Docker or heavy daemon required. Create, use, and dispose of VMs directly from your code.
Quickstart
Python
# Fetches the console server into virtx's cache the first time; a no-op after.
await
= await
= await
Node
import from '@brekkylab/virtx'
// Fetches the console server into virtx's cache the first time; a no-op after.
await
const console_ = await
.
.
try finally
Rust
use ;
async
Output:
step 1/1: cd '/' && apk add --no-cache jq
(1/2) Installing oniguruma (6.9.10-r0)
(2/2) Installing jq (1.8.2-r0)
Executing busybox-1.37.0-r31.trigger
OK: 9426 KiB in 18 packages
virtx
Features
Coverage
| Supported | |
|---|---|
| Languages | 🐍 Python · Node · 🦀 Rust |
| Hosts | 🐧 Linux · 🍎 macOS (Apple silicon) · Windows 11 or later |
| Guest | 🐧 Linux, always |
GPU support
The VM gets a GPU through Vulkan on every host, so it can run heavy work like deep learning.
Turn it on with the builder's gpu option, and install the guest's half of Vulkan in the image:
await
= await
= await
The host's GPU shows up in the guest as Virtio-GPU Venus (<the host's GPU>). What the image needs for that:
| Alpine | Debian | |
|---|---|---|
Vulkan loader (libvulkan.so.1) |
vulkan-loader |
libvulkan1 |
| venus driver | mesa-vulkan-virtio |
mesa-vulkan-drivers, trixie or later |
- Install the loader yourself. Without it, no program in the guest finds a Vulkan device, whatever the host has. Some packages bring it along (Debian's
vulkan-toolsdoes) and some don't (Alpine's doesn't), so name it rather than count on it. - An image with no venus driver still runs, but on the CPU. Debian bookworm's Mesa has no venus, and Vulkan there falls back to
llvmpipe, a software renderer. Check thedeviceNameyour program picks.
If the host can't give a GPU, build() fails instead of quietly running on the CPU. On the host, that takes a Vulkan loader too: libvulkan1 (Debian, Ubuntu) or vulkan-loader (Fedora) on Linux, and on Windows vulkan-1.dll, which comes with the GPU's driver.
Filesystem
Mount a host directory into the VM by passing its path.
= await
= await
Writes to /project land in the host's current directory, while /host-etc is read-only: commands in the VM can read it but not write to it.
Going further, you can build a virtual directory in code and mount it into the VM through FUSE. It mixes files held only in memory with host directories, all under one mount point.
=
=
= await
= await
notes/today.md lives only in memory, and project is the host's current directory.
Moreover, external stores like S3, Google Drive and Notion, and commands inside the VM can read them as ordinary files.
use ;
use FuseMount as HostMount;
use FuseTMount as HostMount;
use DokanMount as HostMount;
async
These stores are Rust only for now, each behind its own feature: s3, gdrive and notion.
S3 is read-only, so it's mounted with mount_readonly.
This feature needs an extra package installed on macOS and Windows.
The mount feature, on by default, mounts a virtx filesystem on the host through the host's FUSE provider:
| Host | Provider | Needed to build | Needed to mount |
|---|---|---|---|
| Linux | /dev/fuse in the kernel |
— | — |
| macOS | FUSE-T | — | ✓ |
| Windows | Dokany | — | ✓ |
A program built with mount runs on a host without the provider; only mounting fails, with an error that says what to install.
virtx::fs::mount_support() (mount_support() in Python, mountSupport() in Node) asks ahead of a mount.
On Windows, a Rust program gets that only if it delay-loads dokan2.dll, which it has to ask for in its own build.rs. virtx's cannot do it on the program's behalf, since a link argument reaches only the package that prints it. The Node and Python packages already do it. Without it, a program that mounts needs Dokany installed just to start.
// build.rs of a program that depends on virtx
If you don't mount on the host, build with default-features = false and skip all of this.
For macOS
virtx mounts through FUSE-T 1.x, and is checked against 1.2.7. A FUSE-T of another major version is refused before a mount, with the release to install instead, rather than risk a crash on a layout that changed; VIRTX_FUSE_T_UNCHECKED=1 mounts with it anyway.
And for windows
winget install --id dokan-dev.Dokany
Cache
virtx keeps all persistent state in a single cache directory that you can safely delete at any time:
| Host | Cache directory |
|---|---|
| Linux | $XDG_CACHE_HOME/virtx, or ~/.cache/virtx |
| macOS | ~/Library/Caches/virtx |
| Windows | %LOCALAPPDATA%\virtx |
Set VIRTX_HOME to put it somewhere else.