Build self-contained Linux apps from containers.
vessel's generated executable contains the image filesystem, OCI runtime config, and
runtime helpers. On supported hosts it starts through a fast SquashFS/FUSE path;
if that is unavailable, it falls back to extracting an embedded tar.zst payload.
We have a demo available for the llama.cpp CUDA server: Hybrid, squashfs-only, and tar.zst-only.
For building applications:
- Linux x86_64
- Rust stable and Cargo
- Go
- C build tools:
gcc,make,autoconf,automake,libtool,pkg-config - development libraries for
fuse3,zstd,seccomp,cap,apparmor,selinux,systemd,yajl, andzlib
Generated applications are self-contained. Users running a vessel-created
binary do not need vessel, skopeo, umoci, crun, squashfuse, or
fuse-overlayfs installed.
Recursively clone:
git clone --recursive https://github.com/dphnAI/vessel.git && cd vesselcargo xtask build-go-helpers
cargo xtask build-zstd-helper
cargo xtask build-mksquashfs
cargo xtask build-runtime
cargo build -p vesselFor a release-style build:
cargo xtask package-releaseThis writes target/vessel-release/x86_64-unknown-linux-gnu/ with vessel,
vessel-runtime, build helpers, VERSION, and SHA256SUMS.
target/debug/vessel build --image docker://hello-world --output hello
./helloThe short form is also accepted:
target/debug/vessel --image docker://busybox --output busybox
./busybox -- -c 'echo hello from busybox'Generated executables support runtime env overrides, bind mounts, and extra process arguments:
./app -e KEY=value -v "$PWD/data:/data" -- --helpGPU passthrough uses the host NVIDIA Container Toolkit through an OCI prestart hook:
target/debug/vessel build --image docker://nvidia/cuda:13.2.0-base-ubuntu24.04 --gpu nvidia --output cuda-app
./cuda-app -- -c nvidia-smi
./app --gpus all -- nvidia-smi
./app --gpus device=0,1 -- nvidia-smi
./app --runtime nvidia -- nvidia-smi--gpu nvidia bundles the NVIDIA Container Toolkit helpers from the build host,
so users running the generated executable need the NVIDIA driver but do not need
nvidia-container-toolkit installed. Rootless GPU runs use direct OCI
device/library mounts; rootful runs can use the bundled NVIDIA hook. The
generated executable requests all GPUs by default; runtime --gpus arguments
can still narrow the selected devices.
Build an arm64 artifact:
cargo xtask build-runtime --arch arm64
target/debug/vessel build --image docker://hello-world --arch arm64 --output hello-arm64This is a good example to demonstrate the GPU build, since most other CUDA images would be quite inflated. llama.cpp's server image can compile to about less than 2GB.
vessel build --image docker://ghcr.io/ggml-org/llama.cpp:server-cuda \
--gpu nvidia \
--output ./llama-server \
--payload-format tar.zstThen run your model with:
./llama-server \
--gpus all \
-v "$PWD/models:/models" \
-- \
-m /models/your-model.gguf \
--host 0.0.0.0 \
--port 8080 \
-ngl 999The -v command is important, as vessel binaries have no access to your files, just like
a normal docker image.
The default payload is SquashFS plus a tar.zst fallback. This gives faster
startup when FUSE and unprivileged user namespaces are available, while keeping
the binary runnable on more restricted hosts.
Choose a payload format at build time:
target/debug/vessel build --image docker://busybox --output busybox --payload-format squashfs
target/debug/vessel build --image docker://busybox --output busybox-squashfs --payload-format squashfs-only
target/debug/vessel build --image docker://busybox --output busybox-tar --payload-format tar.zstsquashfs writes both SquashFS and a tar.zst fallback. Use
squashfs-only for large images where binary size matters more than fallback
compatibility. Use tar.zst for maximum compatibility on restricted hosts.
The VESSEL_PAYLOAD_FORMAT environment variable accepts the same values.
If mksquashfs is unavailable while building, vessel falls back to tar.zst
and prints a warning.
The normal execution path uses the embedded crun helper. The direct fallback
path handles args, env, cwd, bind mounts, user/group IDs, additional groups,
rlimits, noNewPrivileges, umask, basic OCI mounts, read-only rootfs, masked
paths, and read-only paths.
Full OCI features such as cgroups, seccomp, complete capability handling, hooks,
devices, full namespace topology, and complex user mappings are handled by
crun.
Useful runtime knobs:
VESSEL_RUNTIME_DISABLE_CRUN=1 ./app
VESSEL_SQUASHFUSE=/path/to/squashfuse ./app
VESSEL_FUSE_OVERLAYFS=/path/to/fuse-overlayfs ./app
VESSEL_CRUN=/path/to/crun ./app
VESSEL_NVIDIA_HOOK=/path/to/nvidia-container-runtime-hook ./app --gpus allVessel's own source code is MIT licensed. Release archives and generated
executables may include third-party helper binaries under their own licenses;
see THIRD-PARTY.md.
This project was greatly inspired by dockerc.