Skip to main content

VDI β€” desktop pools

corral-vdi is Phase 1 of a small, self-hosted Virtual Desktop Infrastructure built entirely on Corral primitives you already have: corral bootc (desktop Linux images), corral-windows (Windows guests), noVNC/RDP console bridges, and Tailscale exposure. This isn't a Citrix/Horizon/oVirt competitor β€” it's "good VDI for personal or small-team use," scoped to what fits in one Go binary and a tailnet.

Design doc: RFC-0001. Tracking issue: #69.

Mental model​

A pool is not a new kind of object β€” it's just VMs with a corral.dev/vdi-pool=<name> label. There's no pool CRD, no controller, no reconciliation loop watching anything. corral vdi pool create clones N VMs and labels them; pool list reads the labels back; pool delete deletes the labeled VMs. If you're ever unsure what a command did, kubectl get vm -n <ns> -l corral.dev/vdi-pool shows you the truth directly β€” there's no other state to go stale.

Assignment works the same way: a corral.dev/vdi-assigned-to=<user> label plus a corral.dev/vdi-claimed-at timestamp annotation on the member VM. Nothing lives outside the Kubernetes API.

Install​

corral plugin install vdi

Prerequisites​

  • A golden VM β€” an already-built, already-working VM you want to make copies of. Build it the normal way:
    • Desktop Linux: corral bootc create mydesktop --image ghcr.io/ublue-os/bluefin:latest
    • Windows: corral windows create mydesktop --iso <url> β€” see the Windows plugin guide for ISO sourcing
    • Anything else: corral create mydesktop --kubevirt ...
  • KubeVirt's clone feature needs a VolumeSnapshotClass for persistent-disk VMs β€” corral doctor flags a missing one before you find out the hard way.

Walkthrough​

# 1. Build (or reuse) a golden VM, customize it, then stop it β€” clone from
# a stopped VM for a clean disk state.
corral bootc create golden-desktop --image ghcr.io/ublue-os/bluefin:latest
corral start golden-desktop
# ...install packages, configure things...
corral stop golden-desktop

# 2. Create a pool of 3 clones.
corral vdi pool create devpool --from golden-desktop --size 3

# 3. See what's in it.
corral vdi pool list
# devpool (ns/corral-vms, 3 members)
# devpool-1 free stopped
# devpool-2 free stopped
# devpool-3 free stopped

# 4. Hand one to a user β€” starts it if it was stopped.
corral vdi assign devpool alice
# assigned devpool-1 β†’ alice
# connect: corral vdi connect devpool-1

# 5. Connect β€” prints every reachable path, pick what fits the guest.
corral vdi connect devpool-1

# 6. Release it when done. Unassign always stops the VM β€” pooled desktops
# don't stay running unclaimed.
corral vdi unassign devpool-1

# 7. Tear the whole pool down when you're finished with it.
corral vdi pool delete devpool

What "connect" does today​

corral vdi connect <member> prints instructions β€” it doesn't yet pick a protocol and open a session for you automatically. One-click routing is Phase 2 territory, and depends on in-browser RDP landing first (see ADR-0002) so Windows members get the same one-click experience VNC already gives Linux members. Until then:

GuestHow to connect
Any VMcorral web β†’ open the VM β†’ Console tab (noVNC in the browser) β€” always works
Linux VM with RDP configuredThe VM's Summary panel shows whether port 3389 answers; connect with a native RDP client via virtctl port-forward
Windows VMSame RDP path β€” corral-windows-created VMs expose RDP through the proxy service
Any VM with SSHcorral ssh <member>

Troubleshooting​

  • golden VM "X" not found β€” the --from VM doesn't exist in the target namespace. Pass -n to match wherever it actually lives.
  • timed out ... waiting for the clone to produce VM β€” KubeVirt's clone controller didn't produce the target VM within 2 minutes. Check kubectl get virtualmachineclone -n <ns> β€” a stuck clone is almost always a StorageClass/VolumeSnapshotClass issue.
  • pool has no free members β€” every member is claimed. corral vdi unassign one, or create a bigger pool (no live resize yet).
  • Assigned member won't start β€” assign surfaces the underlying virtctl start error directly. The assignment label is still set even if start failed; unassign to back out and retry.

Current limitations (Phase 1 β€” by design)​

  • No self-serve "get a desktop" page β€” assignment is a CLI/admin action.
  • No idle/logout reclaim β€” nothing notices "alice hasn't touched devpool-1 in 3 hours" and reclaims it automatically.
  • No live pool resize β€” delete and recreate, or clone one more member by hand.
  • No GPU-gating on pool create β€” if the golden VM needs a GPU, every clone needs one too; nothing stops you from over-provisioning.
  • CT-backed pools aren't implemented β€” only VM golden sources work today.

None of this is hidden. Full phased plan: RFC-0001.