Skip to content

dphnAI/vessel

Repository files navigation

vessel

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.

Requirements

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, and zlib

Generated applications are self-contained. Users running a vessel-created binary do not need vessel, skopeo, umoci, crun, squashfuse, or fuse-overlayfs installed.

Build

Recursively clone:

git clone --recursive https://github.com/dphnAI/vessel.git && cd vessel
cargo xtask build-go-helpers
cargo xtask build-zstd-helper
cargo xtask build-mksquashfs
cargo xtask build-runtime
cargo build -p vessel

For a release-style build:

cargo xtask package-release

This writes target/vessel-release/x86_64-unknown-linux-gnu/ with vessel, vessel-runtime, build helpers, VERSION, and SHA256SUMS.

Usage

target/debug/vessel build --image docker://hello-world --output hello
./hello

The 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" -- --help

GPU 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-arm64

Example: llama.cpp server

This 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.zst

Then 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 999

The -v command is important, as vessel binaries have no access to your files, just like a normal docker image.

Payload Format

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.zst

squashfs 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.

Runtime Notes

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 all

License

Vessel'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.

Acknowledgements

This project was greatly inspired by dockerc.

About

Compile docker images into a single self-contained binary

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages