Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Declarative Workflow with VMFile.kdl

This tutorial shows how to define VMs in a configuration file and manage them with vmctl up/down.

Write a VMFile

Create VMFile.kdl in your project directory:

vm "webserver" {
    image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
    vcpus 2
    memory 2048
    disk 20

    cloud-init {
        hostname "webserver"
    }

    ssh {
        user "ubuntu"
    }

    provision "shell" {
        inline "sudo apt-get update && sudo apt-get install -y nginx"
    }

    provision "shell" {
        inline "echo 'Hello from vmctl!' | sudo tee /var/www/html/index.html"
    }
}

Bring It Up

vmctl up

vmctl will:

  1. Discover VMFile.kdl in the current directory.
  2. Download the Ubuntu image (or use the cached copy).
  3. Generate an Ed25519 SSH keypair for this VM.
  4. Create a QCOW2 overlay with 20GB disk.
  5. Build a cloud-init ISO with the hostname and generated SSH key.
  6. Boot the VM.
  7. Wait for SSH to become available.
  8. Run the provision steps in order, streaming output to your terminal.

Connect

vmctl ssh

When there's only one VM in the VMFile, you don't need to specify the name.

Make Changes

Edit VMFile.kdl to add another provisioner, then reload:

vmctl reload

This destroys the existing VM and recreates it from scratch with the updated definition.

To re-run just the provisioners without recreating:

vmctl provision

Bring It Down

Stop the VM:

vmctl down

Or stop and destroy:

vmctl down --destroy

Filtering by Name

If your VMFile defines multiple VMs, use --name to target a specific one:

vmctl up --name webserver
vmctl ssh --name webserver
vmctl down --name webserver