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.
kubectlconfigured 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.
-
Inspect existing Storage Classes (if any):
NODE_TYPE // bashkubectl get storageclassNODE_TYPE // outputNAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE AGE standard (default) k8s.io/minikube-hostpath Delete Immediate 2dIf you don’t have any Storage Classes, the output will indicate that no resources were found. -
Examine the details of the default Storage Class (if one exists):
NODE_TYPE // bashkubectl describe storageclass standardNODE_TYPE // outputName: standard IsDefaultClass: Yes Annotations: storageclass.kubernetes.io/is-default-class=true Provisioner: k8s.io/minikube-hostpath Parameters: ReclaimPolicy: Delete VolumeBindingMode: Immediate Events: <none>TheProvisionerfield is critical. It specifies which volume plugin is used for dynamic provisioning. TheReclaimPolicydetermines what happens to the underlying volume when the PersistentVolumeClaim is deleted.VolumeBindingModecontrols 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.
-
Create a Storage Class definition file (e.g.,
my-storage-class.yaml):NODE_TYPE // yamlapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: my-custom-storage provisioner: k8s.io/minikube-hostpath reclaimPolicy: Retain volumeBindingMode: Immediate parameters: type: Directoryname: The name of your StorageClass.provisioner: Specifies the volume plugin to use.reclaimPolicy:Retainmeans the underlying volume will not be deleted when the PVC is deleted.Delete(the default) means it will be deleted.volumeBindingMode:Immediatemeans volume binding happens as soon as the PVC is created.WaitForFirstConsumerdelays volume binding until a Pod using the PVC is created.parameters: Provisioner-specific parameters.
-
Apply the Storage Class:
NODE_TYPE // bashkubectl apply -f my-storage-class.yamlNODE_TYPE // outputstorageclass.storage.k8s.io/my-custom-storage created -
Verify the Storage Class:
NODE_TYPE // bashkubectl get storageclass my-custom-storageNODE_TYPE // outputNAME 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.
-
Create a PVC definition file (e.g.,
my-pvc.yaml):NODE_TYPE // yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: my-custom-storageaccessModes:ReadWriteOncemeans the volume can be mounted as read-write by a single node. Other options includeReadOnlyManyandReadWriteMany.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).
-
Apply the PVC:
NODE_TYPE // bashkubectl apply -f my-pvc.yamlNODE_TYPE // outputpersistentvolumeclaim/my-pvc created -
Verify the PVC:
NODE_TYPE // bashkubectl get pvc my-pvcNODE_TYPE // outputNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-pvc Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 1Gi RWO my-custom-storage 15sNote theSTATUSisBoundand aVOLUMEhas been automatically created (namedpvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). This indicates dynamic provisioning worked! -
Verify the Persistent Volume (PV) has been created:
NODE_TYPE // bashkubectl get pvNODE_TYPE // outputNAME 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 20sThe PV’s name matches theVOLUMEname from the PVC output. TheSTATUSisBound, and theCLAIMfield indicates which PVC is using this PV. TheRECLAIM POLICYisRetain, 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.
-
Create a Pod definition file (e.g.,
my-pod.yaml):NODE_TYPE // yamlapiVersion: 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-volumevolumes.persistentVolumeClaim.claimName: Specifies the PVC to use.volumeMounts.mountPath: The path within the container where the volume will be mounted.
-
Apply the Pod:
NODE_TYPE // bashkubectl apply -f my-pod.yamlNODE_TYPE // outputpod/my-pod created -
Verify the Pod is running:
NODE_TYPE // bashkubectl get pod my-podNODE_TYPE // outputNAME READY STATUS RESTARTS AGE my-pod 1/1 Running 0 10s -
Check the logs to see the data being written
NODE_TYPE // bashkubectl logs my-podNODE_TYPE // outputMon 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
-
Delete the Pod:
NODE_TYPE // bashkubectl delete pod my-pod -
Delete the PVC:
NODE_TYPE // bashkubectl delete pvc my-pvcIf the Storage Class’sreclaimPolicyis set toDelete, this will also delete the underlying Persistent Volume. If it’s set toRetain, the PV will remain, and its contents will be preserved. -
Delete the Storage Class:
NODE_TYPE // bashkubectl 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.