3 Using KubeVirt

This chapter discusses how to use the KubeVirt module to create virtual machines in Oracle Cloud Native Environment.

Creating a Virtual Machine Image

KubeVirt pulls a containerized image from a container registry to create virtual machine instances. You need to prepare these images before you can use them with KubeVirt. This section contains an example of how to create a container image of Oracle Linux that can be used to create a KubeVirt virtual machine.

This example uses an Oracle Linux cloud image in QCOW format from:

https://yum.oracle.com/oracle-linux-templates.html

For example, on any host that can connect to your local container registry, download the Oracle Linux 9 QCOW image:

wget https://yum.oracle.com/templates/OracleLinux/OL9/u2/x86_64/OL9U2_x86_64-kvm-b197.qcow

Create a Dockerfile so you can load the image into your local container registry. For example, in the same directory as the QCOW image is located, create a file named Dockerfile that contains:

FROM scratch
ADD --chown=107:107 OL9U2_x86_64-kvm-b197.qcow  /disk/

Build a containerized image from the QCOW image. For example:

podman build . -t myregistry.example.com/kubevirt/oraclelinux:ol9.2 

You should see output similar to:

STEP 1: FROM scratch
STEP 2: ADD --chown=107:107 OL9U2_x86_64-kvm-b197.qcow  /disk/
STEP 3: COMMIT myregistry.example.com/kubevirt/oraclelinux:ol9.2
--> 09b0b23bb66
Successfully tagged myregistry.example.com/kubevirt/oraclelinux:ol9.2
09b0b23bb6673bdfd1481d81dace0b6008c6ab25e1d156c525b9abaaf8d9f30e

The containerized image is stored locally. You must now upload it to your container registry. If required, log into your container registry:

podman login myregistry.example.com

Push the containerized image to your local registry. For example:

podman push myregistry.example.com/kubevirt/oraclelinux:ol9.2

You should see output similar to:

Getting image source signatures
Copying blob 8a8b1918f588 done  
Copying config 09b0b23bb6 done  
Writing manifest to image destination
Storing signatures

You now have a containerized image for Oracle Linux that you can use to create a KubeVirt virtual machine instance. The container image location in this example is:

myregistry.example.com/kubevirt/oraclelinux:ol9.2

Creating a KubeVirt Instance

This section contains a basic test to verify you can use KubeVirt to create a virtual machine.

This example uses the Oracle Linux 9 container image created in Creating a Virtual Machine Image.

To create a virtual machine with KubeVirt:

  1. Create a VirtualMachine file for your virtual machine. The containerDisk option is where you set the location of the container image to create the virtual machine. This should be the location of a container image in either your local container registry, or a public container registry such as DockerHub. Save the file as vm.yaml.

    apiVersion: kubevirt.io/v1
    kind: VirtualMachine
    metadata:
      name: ol9-no-pvc
    spec:
      running: true
      template:
        spec:
          networks:
          - name: foo
            pod: {}
          domain:
            resources:
              requests:
                memory: 1024M
            firmware:
              bootloader: {}
            features:
              smm:
                enabled: true
            devices:
              interfaces:
              - name: foo
                masquerade: {}
                ports:
                - port: 80
              disks:
              - name: containerdisk
                disk:
                  bus: virtio
          volumes:
          - name: containerdisk
            containerDisk:
              image: myregistry.example.com/kubevirt/oraclelinux:ol9.2
  2. Create the VirtualMachine:

    kubectl apply -f vm.yaml 
    virtualmachine.kubevirt.io/ol9-no-pvc created
  3. You can see the VirtualMachine is created using the kubectl get vm command:

    kubectl get vm
    NAME                           AGE     STATUS    READY
    ol9-no-pvc                     28s     Running   True

    You can see information on the VirtualMachineInstance using the kubectl get vmi command:

    kubectl get vmi
    NAME                    AGE   PHASE     IP              NODENAME              READY
    ol9-no-pvc              48s   Running   10.244.3.19     worker1.example.com   True

    You can get detailed information about the VirtualMachineInstance using the kubectl describe vmi command:

    kubectl describe vmi ol9-no-pvc
    Name:         ol9-no-pvc
    Namespace:    default
    Labels:       kubevirt.io/nodeName=worker1.example.com
    Annotations:  kubevirt.io/latest-observed-api-version: v1
                  kubevirt.io/storage-observed-api-version: v1alpha3
    API Version:  kubevirt.io/v1
    Kind:         VirtualMachineInstance
    ...
      Volumes:
        Container Disk:
          Image:              myregistry.example.com/kubevirt/oraclelinux:ol9.2
          Image Pull Policy:  IfNotPresent
        Name:                 containerdisk
    ...
      Virtual Machine Revision Name:  revision-start-vm-032efda3-040f-4dc0-941d-382daa5f926b-1
      Volume Status:
        Name:    containerdisk
        Target:  sda
    Events:
      Type    Reason            Age   From                       Message
      ----    ------            ----  ----                       -------
      Normal  SuccessfulCreate  94s   virtualmachine-controller  Created virtual machine pod virt-launcher-ol9-no-pvc-sz6hb
      Normal  Created           89s   virt-handler               VirtualMachineInstance defined.
      Normal  Started           89s   virt-handler               VirtualMachineInstance started.

    You can see the pod that is running that maps to the VirtualMachineInstance using:

    kubectl get pod
    NAME                             READY   STATUS    RESTARTS   AGE
    virt-launcher-ol9-no-pvc-....    2/2     Running   0          1h
  4. You can delete the VirtualMachine using:

    kubectl delete vm ol9-no-pvc
    virtualmachine.kubevirt.io "ol9-no-pvc" deleted

Creating a KubeVirt Instance with Persistent Storage

This section contains a basic test to verify you can use KubeVirt to create a virtual machine using persistent storage. This type of virtual machine can be live migrated and the state is maintained.

This example uses the Oracle Linux 9 container image created in Creating a Virtual Machine Image.

This example also uses a CephFilesystem that is available via a StorageClass named rook-cephfs. CephFilesystem is a ReadWriteMany filesystem and is useful to allow writing to the virtual machine filesystem to enable state to be maintained and persist over reboots and live migration. Information on setting up a CephFilesystem using the Rook module is available in Rook Module.

To create a virtual machine that uses persistent storage with KubeVirt:

  1. Create a Kubernetes PersistentVolumeClaim file for your StorageClass. In this example, this is a CephFilesystem StorageClass named rook-cephfs. On a control plane node, create a file named pvc-vm.yaml. Copy the following into the file.

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: ol9-migratable
    spec:
      storageClassName: rook-cephfs
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 30Gi
  2. Create the Kubernetes PersistentVolumeClaim.

    kubectl apply -f pvc-vm.yaml
    persistentvolumeclaim/ol9-migratable created
  3. Create a VirtualMachine file for your virtual machine. This example uses the PersistentVolumeClaim to enable writing to the virtual machine to maintain state. The containerDisk option is where you set the location of the container image to create the virtual machine. This should be the location of a container image in either your local container registry, or a public container registry such as DockerHub. Save the file as vm.yaml.

    apiVersion: kubevirt.io/v1
    kind: VirtualMachine
    metadata:
      name: ol9
    spec:
      running: true
      template:
        spec:
          evictionStrategy: LiveMigrate
          terminationGracePeriodSeconds: 30
          networks:
          - name: foo
            pod: {}
          domain:
            resources:
              requests:
                memory: 1024M
            firmware:
              bootloader: {}
            features:
              smm:
                enabled: true
            devices:
              interfaces:
              - name: foo
                masquerade: {}
                ports:
                - port: 80
              disks:
              - name: containerdisk
                disk:
                  bus: virtio
              - name: installdisk
                disk:
                  bus: virtio
          volumes:
          - name: containerdisk
            containerDisk:
              image: myregistry.example.com/kubevirt/oraclelinux:ol9.2
          - name: installdisk
            persistentVolumeClaim:
              claimName: ol9-migratable
  4. Create the VirtualMachine:

    kubectl apply -f vm.yaml 
    virtualmachine.kubevirt.io/ol9 created
  5. You can see the VirtualMachine is created using the kubectl get vm command:

    kubectl get vm
    NAME                    AGE     STATUS    READY
    ol9                     41m     Running   True

    You can see information on the VirtualMachineInstance using the kubectl get vmi command:

    kubectl get vmi
    NAME                    AGE     PHASE     IP            NODENAME              READY
    ol9                     42m     Running   10.244.3.29   worker1.example.com   True

    You can get detailed information about the VirtualMachineInstance using the kubectl describe vmi command:

    kubectl describe vmi ol9
    Name:         ol9
    Namespace:    default
    Labels:       kubevirt.io/nodeName=worker1.example.com
    Annotations:  kubevirt.io/latest-observed-api-version: v1
                  kubevirt.io/storage-observed-api-version: v1alpha3
    API Version:  kubevirt.io/v1
    Kind:         VirtualMachineInstance
    ...
      Volumes:
        Container Disk:
          Image:              myregistry.example.com/kubevirt/oraclelinux:ol9.2
          Image Pull Policy:  IfNotPresent
        Name:                 containerdisk
        Name:                 installdisk
        Persistent Volume Claim:
          Claim Name:  ol9-migratable
    ...
      Virtual Machine Revision Name:  revision-start-vm-05252d81-e403-4e7b-9834-b9e03850ac7c-1
      Volume Status:
        Name:    containerdisk
        Target:  sda
        Name:    installdisk
        Persistent Volume Claim Info:
          Access Modes:
            ReadWriteMany
          Capacity:
            Storage:            30Gi
          Filesystem Overhead:  0.055
          Requests:
            Storage:    30Gi
          Volume Mode:  Filesystem
        Target:         vda
    Events:
      Type    Reason            Age   From                         Message
      ----    ------            ----  ----                         -------
      Normal  SuccessfulCreate  42m   disruptionbudget-controller  Created PodDisruptionBudget kubevirt-disruption-budget-rgh5f
      Normal  SuccessfulCreate  42m   virtualmachine-controller    Created virtual machine pod virt-launcher-ol9-6qvsh
      Normal  Created           42m   virt-handler                 VirtualMachineInstance defined.
      Normal  Started           42m   virt-handler                 VirtualMachineInstance started.

    You can see the pod that is running that maps to the VirtualMachineInstance using:

    kubectl get pod
    NAME                      READY   STATUS    RESTARTS   AGE
    virt-launcher-ol9-....    2/2     Running   0          1h
  6. You can delete the VirtualMachine using:

    kubectl delete vm ol9
    virtualmachine.kubevirt.io "ol9" deleted