Bootable Volumes

A bootable volume is a ready-to-use boot image that virtual machines can be created from. Each bootable volume is a KubeVirt DataSource (cdi.kubevirt.io/v1beta1) backed by a PVC that CDI populates from an import or clone source. In the console, bootable volumes are managed as image instances — see Adding Image Instances, Managing Image Instances and Image Instances in a Namespace. This page describes them from the API side.

When you create a virtual machine and choose Provision Method > Image Instance, the picker lists the bootable volumes of the shared kube-public namespace — where platform "golden images" live — and of the virtual machine's own namespace.

Notes

  • A bootable volume is offered for virtual-machine creation only when its DataSource carries the virtualization.cpaas.io/* label contract below (at least the operating system and architecture, which the picker filters by), is Ready, and — for a PVC source — its PVC is bound and its import succeeded. A data source without the labels still appears in the image instance list but is not offered in the Image Instance picker.
  • The console shows the import progress as the image instance status: Importing while CDI populates the backing PVC and Available once it can be used; see Status.
  • Local Upload is not a source in the console; upload with virtctl instead (see Uploading a Local Image and Creating a Virtual Machine).

View bootable volumes

Bootable volumes are backed by DataSource objects in kube-public and in the namespaces that hold their own. List them directly:

kubectl get datasource -A

Add a bootable volume

A bootable volume supports these sources; the console names them as listed:

Console sourceWhat it doesDataVolume source
Network > HTTP (or an HTTP image source)Import a qcow2/raw image from an HTTP(S) URLhttp
Network > Registry (or a registry image source)Pull a container disk from a container registryregistry
Network > Object storage (S3) (namespaces only)Import an image from S3-compatible object storage with a credential Secrets3
DiskClone an existing PVCpvc
Volume SnapshotRestore from a VolumeSnapshotsnapshot

Note: Create bootable volumes in your own namespace. The shared kube-public namespace holds platform golden images published by a cluster administrator — users can consume (clone and boot from) kube-public images out of the box, but creating or modifying objects in kube-public requires elevated platform permissions.

Adding a bootable volume creates two objects: a DataVolume (CDI imports the image into a PVC) and a DataSource that points at it and carries the label contract. The example imports an image over HTTP; the console names the DataVolume <name>-img-<5 random characters> and makes the DataSource its owner, while a hand-written pair may share one name as below:

# 1) DataVolume — CDI imports the image into a PVC of the same name.
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: ubuntu-2204
  namespace: demo
spec:
  source:
    http:
      url: https://images.example.com/ubuntu-22.04.qcow2
      # secretRef: my-pull-secret      # for an authenticated source
      # certConfigMap: image-server-ca # for a server with a private CA
  storage:
    resources:
      requests:
        storage: 20Gi
    storageClassName: sc-ceph-cluster-block
    volumeMode: Block
    accessModes:
      - ReadWriteMany
---
# 2) DataSource — makes the PVC selectable as a bootable volume.
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataSource
metadata:
  name: ubuntu-2204
  namespace: demo
  labels:
    virtualization.cpaas.io/image-instance: "true"
    virtualization.cpaas.io/image-os-type: ubuntu
    virtualization.cpaas.io/image-os-arch: amd64
    virtualization.cpaas.io/size: 20Gi
    virtualization.cpaas.io/storage-class: sc-ceph-cluster-block
    virtualization.cpaas.io/volume-mode: Block
    virtualization.cpaas.io/access-mode: ReadWriteMany
    virtualization.cpaas.io/source-type: address   # image-source | address | disk | volume-snapshot
spec:
  source:
    pvc:
      name: ubuntu-2204
      namespace: demo

Choose the volume and access modes the storage class's StorageProfile offers; Block with ReadWriteMany is recommended where available (see Storage settings).

For the other source types, replace spec.source on the DataVolume with one of the following.

Registry:

source:
  registry:
    url: docker://registry.example.com/library/fedora:40

S3, with a Secret holding accessKeyId and secretKey:

source:
  s3:
    url: https://s3.example.com/images/fedora-40.qcow2
    secretRef: s3-images

Clone an existing PVC:

source:
  pvc:
    name: source-pvc
    namespace: demo

Restore from a VolumeSnapshot:

source:
  snapshot:
    name: source-snapshot
    namespace: demo

Apply and watch the import:

kubectl apply -f bootable-volume.yaml
kubectl get datavolume ubuntu-2204 -n demo -w

Default Instance Type and Preference

A bootable volume can declare the instance type and preference that suit it, through labels on its DataSource:

LabelValueWhen absent
instancetype.kubevirt.io/default-instancetypeThe name of the instance typeNo default instance type
instancetype.kubevirt.io/default-instancetype-kindVirtualMachineClusterInstancetype or VirtualMachineInstancetypeVirtualMachineClusterInstancetype
instancetype.kubevirt.io/default-preferenceThe name of the preferenceNo default preference
instancetype.kubevirt.io/default-preference-kindVirtualMachineClusterPreference or VirtualMachinePreferenceVirtualMachineClusterPreference

When you create a virtual machine and select this bootable volume as the image instance, the declared instance type and preference are preselected in the Model area; you can still change them. The form also offers Follow the image, which writes the boot volume as the source of the reference; the platform reads the labels once, when the virtual machine is created (see Creating Virtual Machines). A namespaced instance type or preference can only be used by virtual machines in its own namespace.

CDI copies these labels onto the DataSource from the objects behind it — the PVC and the DataVolume of the same name, or the volume snapshot — and, when the DataVolume carries none of them, from the volume it was imported or cloned from. A label set only on the DataSource is therefore overwritten whenever one of those objects declares another value. In the console, use Update Default Specification on the image instance, which writes the choice on all of them (see Default specification). With kubectl, label the PVC and the DataVolume as well as the DataSource:

for obj in pvc/centos-stream9 datavolume/centos-stream9 datasource/centos-stream9; do
  kubectl label -n kube-public "$obj" --overwrite \
    instancetype.kubevirt.io/default-instancetype=u1.medium \
    instancetype.kubevirt.io/default-preference=centos.stream9
done

Or declare them in the DataSource (and the DataVolume) when you create it:

apiVersion: cdi.kubevirt.io/v1beta1
kind: DataSource
metadata:
  name: centos-stream9
  namespace: kube-public
  labels:
    instancetype.kubevirt.io/default-instancetype: u1.medium
    instancetype.kubevirt.io/default-preference: centos.stream9
spec:
  source:
    pvc:
      name: centos-stream9
      namespace: kube-public

Changing the labels later affects virtual machines created afterwards; existing virtual machines keep the objects they were created with.

Create a virtual machine from a bootable volume

A virtual machine is created in its own namespace and clones its root disk from a bootable volume of kube-public or of that same namespace. Under the hood, the virtual machine references the data source in a dataVolumeTemplates entry — CDI clones the bootable volume into the new virtual machine's root disk:

spec:
  dataVolumeTemplates:
    - metadata:
        name: web-01-rootfs
      spec:
        sourceRef:
          kind: DataSource
          name: ubuntu-2204
          # The bootable volume's namespace: kube-public for an
          # administrator-published golden image, or the virtual machine's own.
          namespace: demo
        storage:
          resources:
            requests:
              storage: 20Gi
          storageClassName: sc-ceph-cluster-block
          volumeMode: Block
          accessModes:
            - ReadWriteMany   # the console picks it from the StorageProfile

The clone source namespace is restricted to the virtual machine's namespace and kube-public. Cloning from another non-public namespace may require additional CDI clone permissions.

Update or delete a bootable volume

In the console, use Re-import and Delete on the image instance; see Managing Image Instances. Deleting an image instance the console added removes its DataSource, and the import DataVolume, its PVC and its CA certificate ConfigMap follow through their owner references.

For a hand-written bootable volume, delete the DataSource and the DataVolume. The backing PVC is owned by the DataVolume (via ownerReferences), so it is garbage-collected automatically when the DataVolume is deleted — do not delete the PVC while the DataVolume still exists, or CDI will re-provision it:

kubectl delete datasource ubuntu-2204 -n demo
kubectl delete datavolume ubuntu-2204 -n demo

If CDI already garbage-collected the DataVolume after a successful import, kubectl delete datavolume returns NotFound and the PVC is left without an owner — delete it directly in that case:

kubectl delete pvc ubuntu-2204 -n demo