Deploy a Virtual Machine#

This deployment procedure is common to Windows and Linux images. It uploads the QCOW2 image that the operating-system-specific procedure prepares and deploys a VM from it.

Holoscan for Media recommends rook-ceph-block as the storage class for the uploaded source PVC and the cloned root disk of each VM. The examples use ReadWriteMany block volumes, which match the recommended Rook Ceph configuration.

Upload the QCOW2 Image#

Upload the release image to a versioned PVC in the VM namespace:

virtctl image-upload pvc <image-pvc-name> \
  --namespace=<vm-project> \
  --image-path=<release-image.qcow2> \
  --size=<virtual-disk-size> \
  --storage-class=rook-ceph-block \
  --access-mode=ReadWriteMany \
  --volume-mode=block \
  --insecure

Set --size to at least the virtual size that qemu-img info reports. Use the virtctl version provided for the KubeVirt environment and run it as the authenticated cluster user without sudo.

Wait for the upload to complete and verify that the PVC is Bound:

kubectl get pvc <image-pvc-name> -n <vm-project>

Create a DataSource from the Uploaded PVC#

Create image-datasource.yaml. Set metadata.name to a versioned image name and set spec.source.pvc.name to the PVC that virtctl image-upload created:

apiVersion: cdi.kubevirt.io/v1beta1
kind: DataSource
metadata:
  name: <image-datasource>
  namespace: <vm-project>
spec:
  source:
    pvc:
      name: <uploaded-image-pvc>
      namespace: <vm-project>

Create and verify the DataSource:

kubectl apply -f image-datasource.yaml
kubectl get datasource <image-datasource> -n <vm-project>

The DataSource is the stable reference to the versioned source image. Create a new PVC and DataSource name for each image release instead of replacing a source that existing deployments use.

Create a VM from the DataSource#

Create virtual-machine.yaml. The dataVolumeTemplates entry clones the DataSource into a dedicated writable root disk for the VM:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: <vm-name>
  namespace: <vm-project>
  labels:
    app: <application-name>
spec:
  runStrategy: Manual
  instancetype:
    kind: VirtualMachineInstancetype
    name: <virtual-machine-instancetype>
  preference:
    kind: VirtualMachineClusterPreference
    name: <operating-system-preference>
  dataVolumeTemplates:
    - metadata:
        name: <vm-name>-rootdisk
      spec:
        sourceRef:
          kind: DataSource
          name: <image-datasource>
          namespace: <vm-project>
        storage:
          accessModes:
            - ReadWriteMany
          resources:
            requests:
              storage: <virtual-disk-size>
          storageClassName: rook-ceph-block
          volumeMode: Block
  template:
    metadata:
      labels:
        app: <application-name>
        kubevirt.io/domain: <vm-name>
    spec:
      domain:
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: <disk-bus>
          interfaces:
            - name: default
              masquerade: {}
      networks:
        - name: default
          pod: {}
      volumes:
        - name: rootdisk
          dataVolume:
            name: <vm-name>-rootdisk

Use the instance type provided for the application. Set <operating-system-preference> to the cluster preference that matches the image. On this cluster, windows.2k22 provides UEFI with Secure Boot, SATA, and e1000e defaults for Windows Server 2022. Use it only for an image that you built with that firmware and device profile. For a VirtIO-built Windows image, use windows.2k22.virtio instead. For Linux, use the preference matching the selected Linux image, such as ubuntu. Set <disk-bus> to the device that you used when you built the image, such as sata or virtio.

Create and start the VM:

kubectl apply -f virtual-machine.yaml
kubectl get datavolume <vm-name>-rootdisk -n <vm-project> --watch
virtctl start <vm-name> -n <vm-project>
kubectl get vm,vmi <vm-name> -n <vm-project>

Wait for the cloned DataVolume phase to become Succeeded before starting the VM. To create another Windows or Linux VM from the same image, use unique VM and root-disk names while keeping sourceRef.name set to the same DataSource.