3_quick-start-rootfs.md
November 2, 2025 ยท View on GitHub
Run unmodified Docker/OCI images as microVMs with hardware isolation. This path provides compatibility with existing container images while adding true VM-level security and deterministic networking.
Install a Prebuilt Image
volar images install --manifest \
https://raw.githubusercontent.com/volantvm/oci-image-example/main/manifest/nginx.json
volar vms create web --image nginx --cpu 2 --memory 1024
Result: a microVM that boots in seconds with an OCI-based root filesystem and full hardware isolation.
Build Your Own Image with Fledge
Install Fledge
curl -LO https://github.com/volantvm/fledge/releases/latest/download/fledge-linux-amd64
chmod +x fledge-linux-amd64 && sudo mv fledge-linux-amd64 /usr/local/bin/fledge
Understanding the Configuration Split
Fledge uses two configuration files:
- fledge.toml - Defines how to build the image (build-time configuration)
- manifest.toml - Defines runtime defaults for VMs created from this image
This separation allows you to:
- Build images once with sensible defaults
- Create many VMs with different configurations
- Override settings without rebuilding
Create Your Project
Create a directory for your image:
mkdir my-oci-app
cd my-oci-app
fledge.toml (Build Configuration)
version = "1"
strategy = "oci_rootfs"
[agent]
source_strategy = "release"
version = "latest"
[source]
image = "docker://nginx:alpine"
[filesystem]
type = "squashfs" # Default: compressed read-only with overlay
compression_level = 15 # 1-22, default 15 (balanced)
overlay_size = "1G" # tmpfs size for runtime writes
You can swap source.image for a Dockerfile build:
[source]
dockerfile = "./Dockerfile"
context = "."
target = "runtime-stage" # Optional multi-stage target
[source.build_args]
APP_VERSION = "1.0.0"
manifest.toml (Runtime Defaults)
schema_version = "v1"
name = "nginx"
version = "0.1.0"
runtime = "nginx"
# Resources section is OPTIONAL - omit to use defaults (cpu_cores=2, memory_mb=2048)
[resources]
cpu_cores = 2
memory_mb = 1024
[workload]
type = "exec" # Can be "exec", "http", or "grpc"
entrypoint = ["/docker-entrypoint.sh", "nginx", "-g", "daemon off;"]
[env]
NGINX_PORT = "80"
LOG_LEVEL = "info"
[[network.expose]]
port = 80
protocol = "tcp"
[[network.expose]]
port = 443
protocol = "tcp"
Build the Image
sudo fledge build
This will:
- Read both fledge.toml and manifest.toml
- Fetch the OCI image or build from Dockerfile
- Unpack layers and install the Kestrel agent
- Create squashfs filesystem image (compressed, read-only with overlay)
- Generate manifest.json and rootfs.squashfs in the dist/ directory
Install and Run
# Install the image
volar images install dist/manifest.json
# Create a VM with defaults from manifest.toml
volar vms create demo --image nginx
# Or create a VM with overrides
volar vms create prod --image nginx \
--cpu 4 \
--memory 2048 \
--env LOG_LEVEL=warn \
--port 8080:80 \
--port 8443:443
# List your VMs
volar vms list
# Check the VM's IP and access your app
volar vms show demo
curl http://<vm-ip>:80
Build Directly from Dockerfile
Skip the config files and build directly from a Dockerfile:
sudo fledge build ./Dockerfile \
--context . \
--target runtime-stage \
--build-arg FOO=bar \
--output my-rootfs
# Outputs: my-rootfs.img + my-rootfs.manifest.json
Note: When using direct CLI builds, you'll need to manually create a manifest.toml or edit the generated manifest.json to set runtime defaults.
Then install and run:
volar images install my-rootfs.manifest.json
volar vms create demo --image my-rootfs
Configuration Override Examples
The three-tier configuration system lets you customize VMs without rebuilding images:
# Development: minimal resources, debug logging
volar vms create dev --image nginx \
--cpu 1 \
--memory 512 \
--env LOG_LEVEL=debug \
--env NGINX_PORT=8080
# Production: more resources, different ports
volar vms create prod --image nginx \
--cpu 8 \
--memory 8192 \
--env LOG_LEVEL=error \
--port 443:80
# Staging: custom environment variables
volar vms create staging --image nginx \
--env UPSTREAM_HOST=staging-backend.internal \
--env CACHE_ENABLED=true
The override hierarchy:
- CLI flags (highest priority) override manifest defaults
- Manifest defaults (from manifest.toml) override system defaults
- System defaults (cpu=2, memory=2048) are the fallback
Filesystem Options
Squashfs (Default & Recommended)
Squashfs is the default filesystem type for OCI rootfs images. It provides:
- Compressed storage (significantly smaller disk usage)
- Read-only base with tmpfs overlay for writes
- Faster deployment (no disk preallocation needed)
[filesystem]
type = "squashfs" # Default
compression_level = 15 # 1-22, default 15 (balanced compression)
overlay_size = "1G" # tmpfs size for runtime writes (default "1G")
Legacy Options (ext4/xfs/btrfs)
For advanced use cases requiring writable disks, ext4/xfs/btrfs are available but require manual disk management:
[filesystem]
type = "ext4" # or "xfs", "btrfs"
size_buffer_mb = 100 # Extra space on top of image size
preallocate = false # Sparse vs preallocated file
Note: These legacy options are only feasible if you manually manage boot disks. For most users pulling pre-built images, squashfs is the practical choice.
Next Steps
- See OCI Rootfs Development Guide for deeper coverage
- Learn about Configuration Hierarchy
- Explore fledge.toml Reference
- Explore manifest.toml Reference
- Learn about Networking
- Set up Cloud-init