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:

  1. Read both fledge.toml and manifest.toml
  2. Fetch the OCI image or build from Dockerfile
  3. Unpack layers and install the Kestrel agent
  4. Create squashfs filesystem image (compressed, read-only with overlay)
  5. 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