Skip to main content
By the end of this page a virtual machine is running in your project’s namespace, cloned from a library image, provisioned by cloud-init at first boot, and reachable on whichever network model you chose — including, if you asked for one, an address that will survive live migration. This page starts where Create a project ended: a namespace of your own, on a supervisor whose Virtualization step is done.
Is the VM already running in VMware vCenter? Move it instead of rebuilding it: Migrate VMs from vSphere.

What this changes on your cluster

A KubeVirt VirtualMachine in your project namespace, a PVC cloned from the library’s golden image, and a Secret holding the cloud-init user data — owned by the VM, so deleting the VM reaps it. Nothing outside the namespace changes, with one exception worth knowing: asking for an identity address claims an IP from the supervisor’s VM-identity pool, which is shared estate.

Before you start

  • The Virtualization step, from onboarding — KubeVirt and CDI.
  • A project namespace. Leave the namespace empty and the VM lands in default, which is not a tenant boundary and not what you want.
  • An image in the library with status: ready. A cloning image is not usable yet, and the create call refuses it by name.
  • Permissions: vm:Create, scoped supervisor:<name>:vm:*.
If you want live migration or an identity address, the image must be ReadWriteMany. An RWO image cannot move between nodes, and the create call says so outright: “identity network requires a live-migratable image (ReadWriteMany storage); image <name> is ReadWriteOnce”. Celum’s own end-to-end suite filters RWO images out before it picks one, for exactly this reason.

The shape of it

Pick an image → size it → choose the network → say what runs at first boot → create. The network choice is the one that is expensive to change afterwards.

Step 1 — Pick an image

Three fields on a library image decide whether it is the one you want:
Workloads → New workload → Virtual machine. The image picker lists the VM library.
The Create Virtual Machine form on supervisor prod with Name and Project, image cards marked Ready to boot (Ubuntu 26.04 cloud image, a golden image, Windows Server 2022), disk size and storage class, instance type u1.nano, network mode NAT, Bridge or passt, and the first-boot SSH public keys

Create Virtual Machine: image, disks, instance type, network mode and first boot on one form

Result: an image id. Everything after this point is a decision about how to run it.

Step 2 — Size it

instanceType and diskSize are the two you set; storageClass falls back to the supervisor’s default when empty. Instance types come in families, and the family prefix tells you what it promises:
Every family promising dedicated CPUs — cx, n, rt, d — only schedules on nodes whose CPU manager is enabled. If a VM on one of those sits Pending with nothing else wrong, that is the first thing to check; u and o have no such requirement.
diskSize defaults to 20Gi when omitted.

Step 3 — Choose the network model

Three modes, and the difference between them is not a preference — it decides whether the VM can ever move. bridge drops the eviction strategy, deliberately: an eviction strategy on a VM that cannot migrate would wedge a node drain. So choosing bridge is choosing a VM that pins to its node, and the cost surfaces at maintenance time rather than at create time.
passt needs a node-level prerequisite. It requires unprivileged user namespaces, and Talos hardening ships user.max_user_namespaces=0 — passt then dies with “Couldn’t create user namespace: EPERM”. A machine-config sysctl is needed before this mode works on a Talos supervisor.
An identity address — identityNetwork: true plus an identityPool — gives the VM a routable /32 that follows it through live migration, with no LoadBalancer involved. The claim is allocated before the VM object is created, so a bad pool, an exhausted one, or a non-migratable image fails cleanly with nothing half-made. Combining identity with bridge or passt is allowed but logged as experimental: the claim’s NAT chain was built for the masquerade network layout and is untested against the other two.

Step 4 — Say what runs at first boot

Cloud-init is injected as KubeVirt cloudInitNoCloud. You can pass sshKeys, a password, startupCommands, or a cloudInitTemplateId with cloudInitVariables — a stored template rendered and prepended to the startup commands. Render it first if you are unsure; the preview is a separate call precisely so a broken template fails before a VM exists. installGuestAgent defaults to true on Linux, and it is worth leaving on: guest IP and OS reporting, graceful shutdown, snapshots, and the process and listening-port views all depend on it. Windows goldens get Hyper-V enlightenments and WinRM automatically. rootPartitions carve extra partitions on the boot disk; dataDisks attach, format and mount additional blank disks.

Step 5 — Create it

Workloads → New workload → Virtual machine, then Create VM.
The namespace comes from the body, and defaults to default. If you also pass ?namespace= on the URL it must name the same namespace, or the call is refused — the query parameter is what the authorisation check reads, so a mismatch would mean authorising against a project you hold and creating in one you do not.
Refusals worth recognising: Result: 201 {"status": "created"}. That means the objects were applied — not that the VM is running. Provisioning continues in the background.

Verify

The VM reaches Running. Poll it rather than assuming; the 201 was an apply. The identity address is stamped. It is written at create time, but not necessarily visible on the first read — Celum’s own suite waits for identityIP to appear before wiring a second VM to it. Read it back rather than computing it. The guest agent is reporting. Guest IP, OS and process views only populate once it is up, and its absence is the usual explanation for a VM that looks half-blank in the console.
GET /api/supervisors/{name}/vms for status; the VM detail page for identityIP, identityPool and identityStale.

If you need to undo it

Deleting the VM removes it and reaps its cloud-init Secret through the owner reference. There is no MCP tool for deleting a VM, and that is policy rather than an oversight: no tool in the catalog destroys data. Deleting requires a person, in the dashboard or over the API with vm:Delete. Volumes are separate and deliberate: detaching a disk is not deleting it, and the two are different permissions (vm:Eject covers both detach and delete-volume). Check which one you are pressing.

What commonly goes wrong

Next

VM lifecycle

Start, stop, resize, live-migrate, snapshot, clone and move between projects.

VM networking

Publishing a VM port through a LoadBalancer or a Gateway.

VM storage & disks

Attaching and mounting volumes — and which operations destroy data.

VM identity pools

The pools the claim addresses come from.

Migrate VMs from vSphere

Bring existing VMs in from vCenter instead of building them anew.