Configuring local storage for virtual machines

Configure storage for your virtual machines. When configuring local storage, use the hostpath provisioner (HPP).

About the hostpath provisioner (HPP)

When you install the OKD Virtualization Operator, the Hostpath Provisioner Operator is automatically installed. The HPP is a local storage provisioner designed for OKD Virtualization that is created by the Hostpath Provisioner Operator. To use the HPP, you must create a HPP custom resource.

In OKD Virtualization 4.10, the HPP Operator configures the Kubernetes CSI driver. The Operator also recognizes the existing (legacy) format of the custom resource.

The legacy HPP and the CSI host path driver are supported in parallel for a number of releases. However, at some point, the legacy HPP will no longer be supported. If you use the HPP, plan to create a storage class for the CSI driver as part of your migration strategy.

If you upgrade to OKD Virtualization version 4.10 on an existing cluster, the HPP Operator is upgraded and the system performs the following actions:

  • The CSI driver is installed.

  • The CSI driver is configured with the contents of your legacy custom resource.

If you install OKD Virtualization version 4.10 on a new cluster, you must perform the following actions:

  • Create the HPP custom resource including a storagePools stanza in the HPP custom resource.

  • Create a storage class for the CSI driver.

Create the HPP custom resource with a storage pool

Storage pools allow you to specify the name and path that are used by the CSI driver.

Procedure

  1. Create a YAML file for the HPP custom resource with a storagePools stanza in the YAML. For example:

    1. $ touch hostpathprovisioner_cr.yaml
  2. Edit the file. For example:

    1. apiVersion: hostpathprovisioner.kubevirt.io.v1beta1
    2. kind: HostPathProvisioner
    3. metadata:
    4. name: hostpath-provisioner
    5. spec:
    6. imagePullPolicy: IfNotPresent
    7. storagePools: (1)
    8. - name: <any_name>
    9. path: "</var/myvolumes>" (2)
    10. workload:
    11. nodeSelector:
    12. kubernetes.io/os: linux
    1The storagePools stanza is an array to which you can add multiple entries.
    2Create directories under this node path. Read/write access is required. Ensure that the node-level directory (/var/myvolumes) is not on the same partition as the operating system. If it is on the same partition as the operating system, users can potentially fill the operating system partition and impact performance or cause the node to become unstable or unusable.
  3. Save the file and exit.

Creating a storage class

When you create a storage class, you set parameters that affect the dynamic provisioning of persistent volumes (PVs) that belong to that storage class.

In order to use the host path provisioner (HPP) you must create an associated storage class for the CSI driver with the storagePools stanza.

You cannot update a StorageClass object’s parameters after you create it.

Virtual machines use data volumes that are based on local PVs. Local PVs are bound to specific nodes. While the disk image is prepared for consumption by the virtual machine, it is possible that the virtual machine cannot be scheduled to the node where the local storage PV was previously pinned.

To solve this problem, use the Kubernetes pod scheduler to bind the PVC to a PV on the correct node. By using the StorageClass value with volumeBindingMode parameter set to WaitForFirstConsumer, the binding and provisioning of the PV is delayed until a pod is created using the PVC.

Creating a storage class for the CSI driver with the storagePools stanza

Use this procedure to create a storage class for use with the HPP CSI driver implementation. You must create this storage class to use HPP in OKD Virtualization 4.10 and later.

Procedure

  1. Create a YAML file for defining the storage class. For example:

    1. $ touch <storageclass_csi>.yaml
  2. Edit the file. For example:

    1. apiVersion: storage.k8s.io/v1
    2. kind: StorageClass
    3. metadata:
    4. name: hostpath-csi (1)
    5. provisioner: kubevirt.io.hostpath-provisioner (2)
    6. reclaimPolicy: Delete (3)
    7. volumeBindingMode: WaitForFirstConsumer (4)
    8. parameters:
    9. storagePool: <any_name> (5)
    1Assign any meaningful name to the storage class. In this example, csi is used to specify that the class is using the CSI provisioner instead of the legacy provisioner. Choosing descriptive names for storage classes, based on legacy or CSI driver provisioning, eases implementation of your migration strategy.
    2The legacy provisioner uses kubevirt.io/hostpath-provisioner. The CSI driver uses kubevirt.io.hostpath-provisioner.
    3The two possible reclaimPolicy values are Delete and Retain. If you do not specify a value, the storage class defaults to Delete.
    4The volumeBindingMode parameter determines when dynamic provisioning and volume binding occur. Specify WaitForFirstConsumer to delay the binding and provisioning of a PV until after a pod that uses the persistent volume claim (PVC) is created. This ensures that the PV meets the pod’s scheduling requirements.
    5<any_name> must match the name of the storage pool, which you define in the HPP custom resource.
  3. Save the file and exit.

  4. Create the StorageClass object:

    1. $ oc create -f <storageclass_csi>.yaml

Creating a storage class for the legacy hostpath provisioner

Use this procedure to create a storage class for the legacy hostpath provisioner (HPP). You do not need to explicitly add a storagePool parameter.

Procedure

  1. Create a YAML file for defining the storage class. For example:

    1. $ touch storageclass.yaml
  2. Edit the file. For example:

    1. apiVersion: storage.k8s.io/v1
    2. kind: StorageClass
    3. metadata:
    4. name: hostpath-provisioner (1)
    5. provisioner: kubevirt.io/hostpath-provisioner
    6. reclaimPolicy: Delete (2)
    7. volumeBindingMode: WaitForFirstConsumer (3)
    1Assign any meaningful name to the storage class. In this example, csi is used to specify that the class is using the CSI provisioner, instead of the legacy provisioner. Choosing descriptive names for storage classes, based on legacy or CSI driver provisioning, eases implementation of your migration strategy.
    2The two possible reclaimPolicy values are Delete and Retain. If you do not specify a value, the storage class defaults to Delete.
    3The volumeBindingMode value determines when dynamic provisioning and volume binding occur. Specify the WaitForFirstConsumer value to delay the binding and provisioning of a PV until after a pod that uses the persistent volume claim (PVC) is created. This ensures that the PV meets the pod’s scheduling requirements.
  3. Save the file and exit.

  4. Create the StorageClass object:

    1. $ oc create -f storageclass.yaml

Additional resources

In addition to configuring a basic storage pool for use with the HPP, you have the option of creating single storage pools with the pvcTemplate specification as well as multiple storage pools.

Creating a storage pool using a pvcTemplate specification in a host path provisioner (HPP) custom resource.

If you have a single large persistent volume (PV) on your node, you might want to virtually divide the volume and use one partition to store only the HPP volumes. By defining a storage pool using a pvcTemplate specification in the HPP custom resource, you can virtually split the PV into multiple smaller volumes, providing more flexibility in data allocation.

The pvcTemplate matches the spec portion of a persistent volume claim (PVC). For example:

  1. apiVersion: v1
  2. kind: PersistentVolumeClaim
  3. metadata:
  4. name: "iso-pvc"
  5. labels:
  6. app: containerized-data-importer
  7. annotations:
  8. cdi.kubevirt.io/storage.import.endpoint: "http://cdi-file-host.cdi:80/tinyCore.iso.tar"
  9. spec: (1)
  10. volumeMode: Block
  11. storageClassName: <any_storage_class>
  12. accessModes:
  13. - ReadWriteOnce
  14. resources:
  15. requests:
  16. storage: 5Gi
1A pvcTemplate is the spec (specification) section of a PVC

The Operator creates a PVC from the PVC template for each node containing the HPP CSI driver. The PVC created from the PVC template consumes the single large PV, allowing the HPP to create smaller dynamic volumes.

You can create any combination of storage pools. You can combine standard storage pools with storage pools that use PVC templates in the storagePools stanza.

Procedure

  1. Create a YAML file for the CSI custom resource specifying a single pvcTemplate storage pool. For example:

    1. $ touch hostpathprovisioner_cr_pvc.yaml
  2. Edit the file. For example:

    1. apiVersion: hostpathprovisioner.kubevirt.io/v1beta1
    2. kind: HostPathProvisioner
    3. metadata:
    4. name: hostpath-provisioner
    5. spec:
    6. imagePullPolicy: IfNotPresent
    7. storagePools: (1)
    8. - name: <any_name>
    9. path: "</var/myvolumes>" (2)
    10. pvcTemplate:
    11. volumeMode: Block (3)
    12. storageClassName: <any_storage_class> (4)
    13. accessModes:
    14. - ReadWriteOnce
    15. resources:
    16. requests:
    17. storage: 5Gi (5)
    18. workload:
    19. nodeSelector:
    20. kubernetes.io/os: linux
    1The storagePools stanza is an array to which you can add multiple entries.
    2Create directories under this node path. Read/write access is required. Ensure that the node-level directory (/var/myvolumes) is not on the same partition as the operating system. If it is, users of the volumes can potentially fill the operating system partition and cause the node to impact performance, become unstable, or become unusable.
    3volumeMode parameter is optional and can be either Block or Filesystem but must match the provisioned volume format, if used. The default value is Filesystem. If the volumeMode is block, the mounting pod creates an XFS file system on the block volume before mounting it.
    4If the storageClassName parameter is omitted, the default storage class is used to create PVCs. If you omit storageClassName, ensure that the HPP storage class is not the default storage class.
    5You can specify statically or dynamically provisioned storage. In either case, ensure the requested storage size is appropriate for the volume you want to virtually divide or the PVC cannot be bound to the large PV. If the storage class you are using uses dynamically provisioned storage, pick an allocation size that matches the size of a typical request.
  3. Save the file and exit.

Additional resources