Kubernetes Persistent Volumes and Storage Classes

4 Nov 2026, 11:2715 min readby ITYantra Admin

Complete guide to Kubernetes storage including PersistentVolumes, PersistentVolumeClaims, StorageClasses, CSI, and stateful application deployment.

# Kubernetes Persistent Volumes and Storage Classes

Introduction

Kubernetes provides storage abstractions for stateful applications that need data persistence beyond pod lifecycles. This tutorial covers PersistentVolumes, PersistentVolumeClaims, StorageClasses, CSI, and stateful application deployment patterns.

Learning Objectives

By the end of this tutorial, you will be able to:

  • Explain Kubernetes storage architecture
  • Create PersistentVolumes and PersistentVolumeClaims
  • Configure StorageClasses for dynamic provisioning
  • Deploy stateful applications with StatefulSets
  • Use CSI drivers for cloud storage
  • Implement volume snapshots and backups
  • Choose appropriate storage types for workloads

Technical Background

Kubernetes Storage Architecture

flowchart TD
    PV[PersistentVolume] -->|Bound by| PVC[PersistentVolumeClaim]
    PVC -->|Used by| Pod[Pod]
    SC[StorageClass] -->|Provisions| PV
    CSI[CSI Driver] -->|Interfaces with| Cloud[Cloud Storage]
    
    subgraph Storage Layer
    PV
    PVC
    SC
    CSI
    end

Storage Objects

| Object | Description | |--------|-------------| | PersistentVolume (PV) | Cluster-wide storage resource | | PersistentVolumeClaim (PVC) | User request for storage | | StorageClass | Defines storage type and provisioner | | CSI | Container Storage Interface | | VolumeSnapshot | Point-in-time copy of volume |

Prerequisites

  • Running Kubernetes cluster
  • kubectl configured
  • Cloud provider or on-premises storage

Hardware and Software Requirements

| Component | Requirement | |-----------|-------------| | Kubernetes Cluster | v1.25+ | | Storage Backend | NFS, AWS EBS, Azure Disk, GCP PD, or on-premises | | CSI Driver | Appropriate driver for storage backend |

Step-by-Step Implementation

Phase 1: Static PersistentVolume

# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    server: 192.168.1.100
    path: /exports/k8s

Phase 2: PersistentVolumeClaim

# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 10Gi

Phase 3: StorageClass for Dynamic Provisioning

#### AWS EBS StorageClass

# storageclass-aws.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-standard
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

#### Azure Disk StorageClass

# storageclass-azure.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: azure-standard
provisioner: disk.csi.azure.com
parameters:
  skuName: Premium_LRS
  cachingmode: ReadOnly
reclaimPolicy: Delete
allowVolumeExpansion: true

Phase 4: Use PVC in Pod

# pod-with-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-storage
spec:
  containers:
  - name: app
    image: nginx:latest
    volumeMounts:
    - name: storage
      mountPath: /data
  volumes:
  - name: storage
    persistentVolumeClaim:
      claimName: my-pvc

Phase 5: StatefulSet for Stateful Applications

# statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password
        volumeMounts:
        - name: db-storage
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: db-storage
    spec:
      accessModes: [ReadWriteOnce]
      storageClassName: ebs-standard
      resources:
        requests:
          storage: 100Gi

Phase 6: Volume Snapshots

# volumesnapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: db-snapshot
spec:
  volumeSnapshotClassName: csi-aws-vsc
  source:
    persistentVolumeClaimName: my-pvc

Phase 7: CSI Driver Installation

#### AWS EBS CSI Driver

helm repo add aws-ebs-csi-driver https://kubernetes-sigs.github.io/aws-ebs-csi-driver
helm install aws-ebs-csi-driver aws-ebs-csi-driver/aws-ebs-csi-driver \
  --namespace kube-system --create-namespace

Expected Output

  • PersistentVolumes and Claims configured
  • StorageClasses for dynamic provisioning
  • Stateful applications with persistent storage
  • Volume snapshots for backup
  • CSI drivers installed

Verification Procedures

| Check | Command | Expected Result | |-------|---------|-----------------| | PV status | `kubectl get pv` | Available or Bound | | PVC status | `kubectl get pvc` | Bound | | StorageClass | `kubectl get storageclass` | Classes listed | | Volume mounted | `kubectl exec <pod> -- df -h` | Volume mounted |

Troubleshooting Scenarios

| Issue | Diagnosis | Resolution | |-------|-----------|------------| | PVC Pending | No matching PV or StorageClass | Create PV or configure StorageClass | | Volume not mounting | Wrong mount path or permissions | Check volumeMount; verify permissions | | CSI driver not found | Driver not installed | Install appropriate CSI driver | | Volume expansion denied | allowVolumeExpansion not set | Update StorageClass; recreate PVC |

Best Practices

  • **Use StorageClasses:** Enable dynamic provisioning
  • **Set reclaim policy:** Retain or Delete based on needs
  • **Enable volume expansion:** Allow PVC growth
  • **Use WaitForFirstConsumer:** Bind volume when pod scheduled
  • **Backup regularly:** Use volume snapshots
  • **Choose right access mode:** RWO, ROX, or RWX based on needs

Security Considerations

  • **Encryption at rest:** Enable storage encryption
  • **Access control:** Restrict PVC access by namespace
  • **Snapshot security:** Protect snapshot storage
  • **CSI driver security:** Use verified CSI drivers

Conclusion

Kubernetes storage provides flexible, persistent storage for stateful applications. By understanding PersistentVolumes, PersistentVolumeClaims, StorageClasses, and CSI, you can deploy databases and other stateful workloads reliably on Kubernetes.

References

  • Kubernetes Storage: https://kubernetes.io/docs/concepts/storage/
  • Persistent Volumes: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
  • CSI: https://kubernetes-csi.github.io/docs/
  • StatefulSets: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
#volumes#stateful-applications#csi#storage-class#pvc#persistent-volume#storage#Kubernetes