πŸ“š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 ⏱ 10 minutes K8s 1.28+

K8s PersistentVolumeClaimSpec Reference

Complete PersistentVolumeClaimSpec reference for Kubernetes. accessModes, storageClassName, resources, selector, volumeMode, and dataSource explained.

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

πŸ’‘ Quick Answer: PersistentVolumeClaimSpec defines storage requirements: accessModes (ReadWriteOnce/ReadWriteMany/ReadOnlyMany), resources.requests.storage (size like 10Gi), storageClassName (which provisioner to use), and optionally volumeMode (Filesystem or Block), selector (bind to specific PV), and dataSource (clone or snapshot). Most PVCs only need accessModes + storage size + storageClassName.

The Problem

PVC specs have many fields and it’s unclear which are required, what values are valid, and how they interact with StorageClasses and PVs.

The Solution

Minimal PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-data
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard

Complete PersistentVolumeClaimSpec

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-data
  namespace: production
spec:
  # Required: How the volume can be mounted
  accessModes:
  - ReadWriteOnce          # Single node read-write
  # - ReadWriteMany        # Multiple nodes read-write (NFS, CephFS)
  # - ReadOnlyMany         # Multiple nodes read-only
  # - ReadWriteOncePod     # Single pod read-write (K8s 1.27+)
  
  # Required: Storage size
  resources:
    requests:
      storage: 10Gi        # Minimum size
    # limits:              # Optional β€” rarely used
    #   storage: 20Gi
  
  # Which StorageClass to use (omit for cluster default)
  storageClassName: gp3-encrypted
  # storageClassName: ""   # Empty string = bind to pre-provisioned PV only
  
  # Filesystem (default) or Block
  volumeMode: Filesystem
  # volumeMode: Block      # Raw block device β€” no filesystem
  
  # Bind to specific PV (static provisioning)
  # selector:
  #   matchLabels:
  #     app: database
  #   matchExpressions:
  #   - key: environment
  #     operator: In
  #     values: ["production"]
  
  # Clone from existing PVC or restore from snapshot
  # dataSource:
  #   name: existing-pvc
  #   kind: PersistentVolumeClaim
  # dataSource:
  #   name: my-snapshot
  #   kind: VolumeSnapshot
  #   apiGroup: snapshot.storage.k8s.io
  
  # Cross-namespace clone (K8s 1.29+)
  # dataSourceRef:
  #   name: source-pvc
  #   kind: PersistentVolumeClaim
  #   namespace: other-namespace

Access Modes Comparison

ModeShortNodesUse Case
ReadWriteOnceRWO1 nodeDatabases, single-writer apps
ReadWriteManyRWXMultipleShared data, CMS uploads, ML datasets
ReadOnlyManyROXMultipleConfig files, static assets
ReadWriteOncePodRWOP1 podStrict single-writer (K8s 1.27+)

StorageClass Examples

# List available StorageClasses
kubectl get storageclass
# NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE
# gp3 (default)   ebs.csi.aws.com        Delete          WaitForFirstConsumer
# efs-sc          efs.csi.aws.com        Retain          Immediate
# standard        kubernetes.io/gce-pd    Delete          Immediate

# See default StorageClass
kubectl get sc -o jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}'

Use in Pods

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: myapp:v1
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: my-data      # References the PVC
      readOnly: false

---
# StatefulSet with volumeClaimTemplates (auto-creates PVCs)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: database
spec:
  serviceName: database
  replicas: 3
  template:
    spec:
      containers:
      - name: db
        volumeMounts:
        - name: data
          mountPath: /var/lib/db
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:                      # This IS the PersistentVolumeClaimSpec
      accessModes: ["ReadWriteOnce"]
      storageClassName: gp3-encrypted
      resources:
        requests:
          storage: 50Gi

Volume Expansion

# Check if StorageClass allows expansion
kubectl get sc gp3 -o jsonpath='{.allowVolumeExpansion}'
# true

# Expand PVC (only increase β€” shrinking not supported)
kubectl patch pvc my-data -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'

# Check expansion status
kubectl get pvc my-data -o yaml | grep -A5 conditions

Common Issues

PVC stuck in Pending

Check events: kubectl describe pvc my-data. Common causes: no matching StorageClass, no capacity, WaitForFirstConsumer binding mode (needs a pod to schedule first).

β€œstorageClassName must be provided” error

No default StorageClass set. Either specify one explicitly or mark a StorageClass as default.

accessMode mismatch

PV and PVC accessModes must be compatible. EBS only supports RWO β€” if you need RWX, use EFS, NFS, or CephFS.

Best Practices

  • Always specify storageClassName β€” don’t rely on default (it can change)
  • Use ReadWriteOncePod for databases β€” prevents accidental multi-attach
  • Set WaitForFirstConsumer on StorageClass β€” ensures volume is in the same zone as the pod
  • Use volumeClaimTemplates in StatefulSets β€” automatic per-replica PVCs
  • Enable volume expansion on StorageClass β€” avoid recreating PVCs for resizing

Key Takeaways

  • Most PVCs need only 3 fields: accessModes, storage size, and storageClassName
  • RWO for databases, RWX for shared storage, RWOP for strict single-writer
  • storageClassName: "" binds to pre-provisioned PVs only (no dynamic provisioning)
  • dataSource enables PVC cloning and snapshot restore
  • StatefulSet volumeClaimTemplates spec IS a PersistentVolumeClaimSpec
#storage #pvc #persistent-volumes #storageclass
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