- An OCI containerDisk — a disk image packaged as a normal OCI image and pushed to a registry. Best for reproducibility and reuse.
- An HTTP(S) disk image — a disk file (qcow2, raw, VMDK, VHD, …) hosted at a URL and imported into a persistent disk on first boot. Best for large images or a one‑time “lift and shift.”
Choosing an approach
OCI containerDisk
Reproducible, versioned, and pulled like any other image. Recommended for images you reuse or roll out across many VMs.
HTTP(S) import
No image build step. Point at a URL; Control Plane imports and converts it into a persistent disk. Good for large or one-off images.
Supported source formats
The HTTP(S) importer accepts and auto‑converts these disk formats:| Format | Extensions | Notes |
|---|---|---|
| QEMU copy‑on‑write | .qcow2 | Recommended; compact and sparse. |
| Raw | .img, .raw | Uncompressed full‑size disk. |
| VMware | .vmdk | VMware exports. |
| Hyper‑V | .vhd, .vhdx | Windows/Hyper‑V exports. |
| VirtualBox | .vdi | VirtualBox exports. |
| Optical | .iso | CD/DVD media. |
.gz, .xz) are also accepted and decompressed on import. Both the OCI containerDisk and HTTP(S) paths run the same conversion — CDI converts the source to the boot disk’s native format on import — so you can ship a .vmdk (or .vhd, .vdi, …) directly without converting it first. Converting to qcow2 at build time (see Converting images) is an optional optimization that moves the one-time conversion cost out of the import.
Option A — Publish an OCI containerDisk
A containerDisk is an OCI image whose only contents are a single disk file placed in/disk/. KubeVirt loads that disk as the VM’s boot device.
Obtain a disk image
Use any supported format —
qcow2, raw, vmdk, vhd/vhdx, or vdi. CDI converts it to the boot disk’s native format on import, so no pre-conversion is needed. (Converting to qcow2 first is optional — see Converting images.)Write a Dockerfile
The image is built
FROM scratch with the disk added to /disk/. The disk file must be readable by UID 107 (the qemu user that runs the VM), so set ownership with --chown=107:107:Dockerfile
Nothing else belongs in a containerDisk — no base OS, no entrypoint. The disk file alone is the payload (any supported format). Omitting
--chown=107:107 causes a permission error when KubeVirt tries to open the disk.Build and push to your registry
Build for Or with Docker directly (registry path See Push Images to Registry for authentication and CI/CD details.
linux/amd64 and push to your org’s registry. Using the CLI:ORG.registry.cpln.io/IMAGE:TAG):Option B — Boot from an HTTP(S) image
Host the disk image at an HTTP(S) URL and let Control Plane import it. The import lands in a per‑replica persistent disk, so a boot volume set is required.Host the image
Place the disk file (any supported format) behind an
http(s) URL the cluster can reach — an object store signed URL, a release asset, or a simple web server.Object‑store schemes (
s3://, gs://) are not yet accepted directly — use a signed http(s) URL instead.Converting images
CDI converts disk formats for you on import, so this step is optional — reach for it only to shrink an image or to pay the conversion cost once at build time instead of on every import.qemu-img (from the qemu-utils package) converts between formats:
Building a containerDisk from a converted image
Once converted, package and push it as in Option A:Dockerfile
Windows images
Windows guests work the same way, with a few practicalities:- Set
spec.vm.guestOS: windowsso the correct DNS bootstrap is injected. See Cloud-init & platform injection. - Windows disk images can be large; the HTTP import path avoids building a multi‑GB OCI image.
- A generation‑1 (MBR) VHD boots with
firmware.bootloader: bios; a UEFI image uses the defaultefi. - Ensure VirtIO drivers are present in the image so the guest sees its disk and network. Microsoft’s evaluation VHDs typically need the VirtIO drivers slipstreamed in before upload.
YAML
Next steps
VM Workloads
Configure and run the VM
Volume Sets
Persist boot and data disks
Push Images
Registry authentication and CI/CD
Create a Workload
Deploy from a manifest