Kubevirt is a CNCF sandbox project that allows the running of virtual machines (VMs) in Kubernetes pods.

Deploying Kubevirt using StorageOS offers multiple benefits. Kubevirt can spin up VMs as Kubernetes pods, using images on StorageOS persistent volumes. Doing this allows the VM data to persist through restarts and rescheduling. Using StorageOS volume replicas also allows for failure of nodes holding the PersistentVolume without interrupting the VM running off the PersistentVolume. Containerized Data Importer (CDI) can also be used to prepare StorageOS volumes with disk images in an automated fashion. Simply by declaring that a VirtualMachine will use a DataVolume and providing the disk image URL, a StorageOS volume can be dynamically provisioned and automatically prepared with the disk image.

This usecase will guide you through installing KubeVirt and CDI on your Kubernetes cluster, and create a VM. By the end of the guide you’ll be able to launch a shell inside the KubeVirt VM that’s running as a Kubernetes pod.

Before you start, ensure you have StorageOS installed and ready on a Kubernetes cluster. See our guide on how to install StorageOS on Kubernetes for more information.


Please ensure you have met the Kubevirt prerequisites, please see the Kubevirt installation instructions for more information.

As part of this installation it is assumed that you are running a Kubernetes cluster on VMs. As such nested virtualization or hardware emulation need to be enabled.

Deploying KubeVirt on Kubernetes

For ease of installation we have enabled hardware emulation. If your VMs support nested virtualization then edit the Kubevirt ConfigMap ./kubevirt-install/10-cm.yaml, removing the line debug.useEmulation: "true".

  1. In order to deploy Kubevirt you just need to clone this repository and use kubectl to create the Kubernetes objects.

    $ git clone https://github.com/storageos/use-cases.git storageos-usecases
    $ cd storageos-usecases/kubevirt
    $ kubectl create -f ./kubevirt-install
  2. Check that the Kubevirt pods are running.

    $ kubectl get pods -w -n kubevirt
       NAME                               READY   STATUS    RESTARTS   AGE
       virt-api-57546d479b-p26d4          1/1     Running   0          1m
       virt-api-57546d479b-zs5dw          1/1     Running   0          1m
       virt-controller-56b5498854-7xsfz   1/1     Running   1          1m
       virt-controller-56b5498854-bz559   1/1     Running   1          1m
       virt-handler-6z4kq                 1/1     Running   0          1m
       virt-handler-7szhl                 1/1     Running   0          1m
       virt-handler-jmm6w                 1/1     Running   0          1m
       virt-operator-79c9bdd859-8xq98     1/1     Running   0          1m
       virt-operator-79c9bdd859-kfjz6     1/1     Running   0          1m
  3. Once Kubevirt is running install CDI.

    $ kubectl create -f ./cdi
  4. Check that the CDI pods are running correctly.

    $ kubectl get pods -n cdi
    NAME                              READY   STATUS    RESTARTS   AGE
    cdi-apiserver-8668f888df-s6pp4    1/1     Running   0          1m
    cdi-deployment-5cf794896b-whh4j   1/1     Running   0          1m
    cdi-operator-5887f96c-dz2hg       1/1     Running   0          1m
    cdi-uploadproxy-97fbbfcbf-6f9xs   1/1     Running   0          1m
  5. Now that CDI and Kubevirt are running, VMs can be created. In this example VMs running Cirros, a small and lightweight OS, will be created. The vm-cirros.yaml manifest creates a VirtualMachine that uses a DataVolume. This means that CDI will create a StorageOS backed PVC and download the image that the VirtualMachineInstance (VMI) will boot from onto the PVC.

    $ kubectl create -f ./vm-cirros.yaml
  6. Check that the VMI is running. Note that the VMI will only be created after CDI has downloaded the Cirros disk image onto a StorageOS persistent volume so depending on your connection speed this may take some time.

    $ kubectl get vmi
    NAME     AGE   PHASE     IP            NODENAME
    cirros   1m   Running   ip-10-1-10-154.storageos.net
    $ kubectl get pods
    NAME                         READY   STATUS    RESTARTS   AGE
    virt-launcher-cirros-drqhr   1/1     Running   0          1m
  7. Connect to the VM console.

    This example uses the virtctl kubectl plugin in order to connect to the VMs console. The escape sequence ^] is ctrl + ]

    $ kubectl virt console cirros
    Successfully connected to cirros console. The escape sequence is ^]
    login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
    cirros login: cirros

Cloning Volumes

CDI allows for images to be cloned using a DataVolume manifest. Verify that the cirros pvc, created as part of the vm-cirros.yaml file, exists before attempting to clone the volume.

N.B. Ensure that the VMI is stopped before continuing!

  1. Verify that the VMI is stopped before continuing, and that the cirros pvc, created as part of the vm-cirros.yaml file, exists before attempting to clone the volume.

    $ kubectl get pvc
    NAME    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    cirros  Bound    pvc-f4833060-5a77-420c-927e-6bc518d9df3c   12Gi       RWO            fast           1m
  2. Once the PVC’s existence is confirmed then create a new DataVolume that uses the cirros PVC as its source.

    $ kubectl create -f ./cloned.yaml
  3. Watch as the CDI pods are created.

    $ kubectl get pods -w

    You’ll see that a cdi-upload-cloned-datavolume pod is created and then a cdi-clone-source pod is created. The cdi-source pod mounts the original cirros volume and sends the contents of the volume to the cdi-upload pod. The cdi-upload pod creates and mounts a new PVC and writes the contents of the original volume to it.