πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Storage beginner ⏱ 18 minutes K8s 1.28+

Kubernetes Persistent Volumes Guide

Manage Kubernetes Persistent Volumes with PV, PVC, and StorageClass. Dynamic provisioning, access modes, reclaim policies, and volume expansion.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: PersistentVolume (PV) is the storage, PersistentVolumeClaim (PVC) is the request, StorageClass enables dynamic provisioning. Create a StorageClass, reference it in a PVC, mount the PVC in a pod. Use ReadWriteOnce for single-node (block), ReadWriteMany for shared (NFS/CephFS), and allowVolumeExpansion: true on StorageClass for online resize.

The Problem

Container storage is ephemeral β€” when a pod restarts, all data is lost. Applications need:

  • Data persistence across pod restarts
  • Shared storage between pods
  • Storage provisioned on demand
  • Volume resizing without downtime
  • Different storage tiers (SSD, HDD, NFS)

The Solution

StorageClass (Dynamic Provisioning)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs    # Or csi driver
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
  namespace: production
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 20Gi

Mount in Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:v1
        volumeMounts:
        - name: data
          mountPath: /data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: app-data

Static PersistentVolume (Pre-Provisioned)

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-share
spec:
  capacity:
    storage: 100Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: nfs.example.com
    path: /exports/data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shared-data
spec:
  accessModes:
  - ReadWriteMany
  storageClassName: ""        # Empty = static binding
  resources:
    requests:
      storage: 100Gi

Access Modes

ModeAbbreviationDescription
ReadWriteOnceRWOSingle node read-write
ReadOnlyManyROXMultiple nodes read-only
ReadWriteManyRWXMultiple nodes read-write
ReadWriteOncePodRWOPSingle pod read-write (v1.27+)

Reclaim Policies

PolicyBehavior
DeletePV deleted when PVC is deleted (dynamic default)
RetainPV preserved, must be manually reclaimed
RecycleDeprecated β€” use Delete or Retain

Volume Expansion

# Edit PVC to request more storage
kubectl patch pvc app-data -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'

# StorageClass must have allowVolumeExpansion: true
# For filesystem volumes, pod restart may be needed for resize to take effect
graph LR
    SC[StorageClass<br/>fast-ssd] --> |provisions| PV[PersistentVolume<br/>20Gi gp3]
    PVC[PersistentVolumeClaim<br/>20Gi RWO] --> |binds to| PV
    POD[Pod] --> |mounts| PVC
    
    style SC fill:#2196F3,color:white
    style PV fill:#4CAF50,color:white
    style PVC fill:#FF9800,color:white

Common Issues

PVC stuck in Pending

No matching PV or StorageClass provisioner failing. Check kubectl describe pvc <name> for events. With WaitForFirstConsumer, PVC stays Pending until a pod uses it.

Volume not expanding

StorageClass must have allowVolumeExpansion: true. Some CSI drivers require pod restart for filesystem resize.

Data lost after PVC delete

ReclaimPolicy was Delete. Use Retain for important data and always back up with Velero.

Best Practices

  • Use dynamic provisioning β€” let StorageClass handle PV creation
  • WaitForFirstConsumer β€” ensures PV is in the same zone as the pod
  • Retain for production data β€” prevents accidental deletion
  • Enable volume expansion β€” resize without redeployment
  • RWO for databases, RWX for shared content β€” match access mode to use case
  • Always back up PVs β€” storage is not backup

Key Takeaways

  • PV = storage, PVC = request, StorageClass = dynamic provisioning template
  • Dynamic provisioning creates PVs automatically when PVCs are created
  • WaitForFirstConsumer ensures zone-aware volume placement
  • Volume expansion works online for most CSI drivers
  • Use Retain reclaim policy for data you can’t afford to lose
  • ReadWriteOncePod (v1.27+) provides the strongest single-writer guarantee
#persistent-volumes #storage #pvc #storageclass #fundamentals
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens