Technical Theory

Storage Classes and Dynamic Volume Provisioning

Introduction

This tutorial will guide you through the process of implementing Storage Classes and Dynamic Volume Provisioning in Kubernetes. Dynamic Volume Provisioning allows you to automatically create Persistent Volumes (PVs) when a Persistent Volume Claim (PVC) is created. This eliminates the need to manually create PVs for each PVC, simplifying storage management in your Kubernetes cluster.

Prerequisites:

  • A running Kubernetes cluster.
  • kubectl configured to interact with your cluster.
  • Basic understanding of Kubernetes concepts like Pods, Persistent Volumes, and Persistent Volume Claims.

Task 1: Understanding Storage Classes

A Storage Class provides a way for administrators to describe the “classes” of storage they offer. Different classes might map to different quality-of-service levels, or to backup policies, or to arbitrary policies determined by the cluster administrators. Storage Classes allow dynamic provisioning of Persistent Volumes.

  1. Inspect existing Storage Classes (if any):

    NODE_TYPE // bash
    kubectl get storageclass
    NODE_TYPE // output
    NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE      AGE
    standard (default)   k8s.io/minikube-hostpath   Delete          Immediate              2d
    If you don’t have any Storage Classes, the output will indicate that no resources were found.
  2. Examine the details of the default Storage Class (if one exists):

    NODE_TYPE // bash
    kubectl describe storageclass standard
    NODE_TYPE // output
    Name:                standard
    IsDefaultClass:      Yes
    Annotations:         storageclass.kubernetes.io/is-default-class=true
    Provisioner:         k8s.io/minikube-hostpath
    Parameters:
    ReclaimPolicy:       Delete
    VolumeBindingMode:   Immediate
    Events:              <none>
    The Provisioner field is critical. It specifies which volume plugin is used for dynamic provisioning. The ReclaimPolicy determines what happens to the underlying volume when the PersistentVolumeClaim is deleted. VolumeBindingMode controls when volume binding and dynamic provisioning should occur.

Task 2: Creating a Custom Storage Class

Let’s create a custom Storage Class. This example uses the hostpath provisioner, suitable for development/testing environments like Minikube. Do not use hostpath in production.

  1. Create a Storage Class definition file (e.g., my-storage-class.yaml):

    NODE_TYPE // yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: my-custom-storage
    provisioner: k8s.io/minikube-hostpath
    reclaimPolicy: Retain
    volumeBindingMode: Immediate
    parameters:
      type: Directory
    • name: The name of your StorageClass.
    • provisioner: Specifies the volume plugin to use.
    • reclaimPolicy: Retain means the underlying volume will not be deleted when the PVC is deleted. Delete (the default) means it will be deleted.
    • volumeBindingMode: Immediate means volume binding happens as soon as the PVC is created. WaitForFirstConsumer delays volume binding until a Pod using the PVC is created.
    • parameters: Provisioner-specific parameters.
  2. Apply the Storage Class:

    NODE_TYPE // bash
    kubectl apply -f my-storage-class.yaml
    NODE_TYPE // output
    storageclass.storage.k8s.io/my-custom-storage created
  3. Verify the Storage Class:

    NODE_TYPE // bash
    kubectl get storageclass my-custom-storage
    NODE_TYPE // output
    NAME                PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE      AGE
    my-custom-storage   k8s.io/minikube-hostpath   Retain          Immediate              10s

Task 3: Creating a Persistent Volume Claim

Now, let’s create a Persistent Volume Claim (PVC) that uses our newly created Storage Class. This will trigger dynamic volume provisioning.

  1. Create a PVC definition file (e.g., my-pvc.yaml):

    NODE_TYPE // yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
      storageClassName: my-custom-storage
    • accessModes: ReadWriteOnce means the volume can be mounted as read-write by a single node. Other options include ReadOnlyMany and ReadWriteMany.
    • resources.requests.storage: The amount of storage requested.
    • storageClassName: Crucially, this specifies the Storage Class to use. If omitted, the default Storage Class will be used (if one is configured).
  2. Apply the PVC:

    NODE_TYPE // bash
    kubectl apply -f my-pvc.yaml
    NODE_TYPE // output
    persistentvolumeclaim/my-pvc created
  3. Verify the PVC:

    NODE_TYPE // bash
    kubectl get pvc my-pvc
    NODE_TYPE // output
    NAME     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
    my-pvc   Bound    pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   1Gi        RWO            my-custom-storage   15s
    Note the STATUS is Bound and a VOLUME has been automatically created (named pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). This indicates dynamic provisioning worked!
  4. Verify the Persistent Volume (PV) has been created:

    NODE_TYPE // bash
    kubectl get pv
    NODE_TYPE // output
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS        AGE
    pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   1Gi        RWO            Retain           Bound    default/my-pvc   my-custom-storage   20s
    The PV’s name matches the VOLUME name from the PVC output. The STATUS is Bound, and the CLAIM field indicates which PVC is using this PV. The RECLAIM POLICY is Retain, as defined in the Storage Class.

Task 4: Using the Persistent Volume Claim in a Pod

Now, let’s create a Pod that uses our Persistent Volume Claim.

  1. Create a Pod definition file (e.g., my-pod.yaml):

    NODE_TYPE // yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      volumes:
        - name: my-volume
          persistentVolumeClaim:
            claimName: my-pvc
      containers:
        - name: my-container
          image: busybox
          command: ["/bin/sh", "-c", "while true; do echo $(date) >> /data/output.txt; sleep 5; done"]
          volumeMounts:
            - mountPath: /data
              name: my-volume
    • volumes.persistentVolumeClaim.claimName: Specifies the PVC to use.
    • volumeMounts.mountPath: The path within the container where the volume will be mounted.
  2. Apply the Pod:

    NODE_TYPE // bash
    kubectl apply -f my-pod.yaml
    NODE_TYPE // output
    pod/my-pod created
  3. Verify the Pod is running:

    NODE_TYPE // bash
    kubectl get pod my-pod
    NODE_TYPE // output
    NAME     READY   STATUS    RESTARTS   AGE
    my-pod   1/1     Running   0          10s
  4. Check the logs to see the data being written

    NODE_TYPE // bash
    kubectl logs my-pod
    NODE_TYPE // output
    Mon Apr  7 14:30:21 UTC 2026
    Mon Apr  7 14:30:26 UTC 2026
    Mon Apr  7 14:30:31 UTC 2026
    Mon Apr  7 14:30:36 UTC 2026
    Mon Apr  7 14:30:41 UTC 2026
    Mon Apr  7 14:30:46 UTC 2026

Task 5: Cleaning Up

  1. Delete the Pod:

    NODE_TYPE // bash
    kubectl delete pod my-pod
  2. Delete the PVC:

    NODE_TYPE // bash
    kubectl delete pvc my-pvc
    If the Storage Class’s reclaimPolicy is set to Delete, this will also delete the underlying Persistent Volume. If it’s set to Retain, the PV will remain, and its contents will be preserved.
  3. Delete the Storage Class:

    NODE_TYPE // bash
    kubectl delete storageclass my-custom-storage

Conclusion

You have successfully learned how to implement Storage Classes and Dynamic Volume Provisioning in Kubernetes. You created a custom Storage Class, a Persistent Volume Claim using that Storage Class, and verified that a Persistent Volume was dynamically provisioned. You also learned how to consume the dynamic persistent volume in a Pod. This knowledge will greatly simplify your storage management in Kubernetes, especially in environments with many applications requiring persistent storage.

Next Topic