Persistent Volumes (PVs) and PersistentVolumeClaims (PVCs) provide durable storage that survives Pod restarts and rescheduling. They solve the fundamental tension between Pod ephemerality and data persistence.

The Storage Problem

Pods are ephemeral by design, following the disposable nature of containers. When a Pod dies, its filesystem dies with it. This creates a challenge for stateful applications that need durable data storage.

Without Persistent Volumes:

  • Data lives in container filesystem
  • Pod deletion = data loss
  • Database in a Pod loses all data on restart
  • No way to share data between Pods

With Persistent Volumes:

  • Data lives outside Pod lifecycle
  • Pod deletion preserves data
  • New Pod can mount same volume and access data
  • Multiple Pods can share read-only data

PersistentVolumeClaim (PVC)

PVCs are how applications request storage, serving as a critical runtime dependency. They separate what an application needs from how that storage is provided.

Application perspective (PVC):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: database-storage
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: fast-ssd

This says: “I need 10Gi of storage with ReadWriteOnce access, preferably fast SSD”

Pod mounts the PVC:

volumes:
- name: data
  persistentVolumeClaim:
    claimName: database-storage

The Pod doesn’t know (or care) whether this is AWS EBS, GCE Persistent Disk, NFS, or local storage. The PVC abstracts storage provisioning.

Access Modes

Storage supports different access patterns:

ReadWriteOnce (RWO) - Mount as read-write by a single node

  • Most common for databases
  • Block storage (EBS, GCE PD)
  • One Pod or multiple Pods on same node

ReadOnlyMany (ROX) - Mount as read-only by many nodes

  • Shared configuration or static content
  • Multiple Pods across different nodes

ReadWriteMany (RWX) - Mount as read-write by many nodes

  • Shared filesystems (NFS, CephFS)
  • Multiple Pods need write access
  • More complex, potentially slower

Storage Classes

StorageClasses define different “tiers” of storage with different performance, durability, or cost characteristics:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "10"
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow-hdd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: sc1

PVCs reference a StorageClass to request specific storage characteristics. This enables application portability - the same PVC works across cloud providers, just backed by different storage implementations.

Dynamic vs Static Provisioning

Static Provisioning:

  1. Admin creates PersistentVolume manually
  2. User creates PVC requesting storage
  3. Kubernetes binds PVC to matching PV
  4. Pod mounts the PVC

Dynamic Provisioning:

  1. User creates PVC with StorageClass
  2. Kubernetes automatically creates PV from cloud provider
  3. PVC automatically binds to new PV
  4. Pod mounts the PVC

Dynamic provisioning is standard in cloud environments, eliminating manual PV management.

Lifecycle

PVC lifecycle is independent of Pod lifecycle:

  1. Creation - PVC requests storage, PV is provisioned (dynamically or matched statically)
  2. Binding - PVC binds to PV, becomes available for Pods
  3. Usage - Pods mount and use the PVC
  4. Pod Deletion - Pod dies, PVC remains bound and retains data
  5. PVC Deletion - Policy determines if PV is deleted, retained, or recycled

This independence enables:

  • StatefulSets with durable Pod identities
  • Database Pods that survive restarts
  • Backup and recovery workflows

Resource Quotas

ResourceQuotas can limit PVC usage per Namespace:

spec:
  hard:
    persistentvolumeclaims: "10"
    requests.storage: "100Gi"

This prevents teams from over-provisioning expensive storage.

Relationship to Twelve-Factor

Twelve-factor apps treat backing services as attached resources. PVCs embody this - storage is declared as a runtime dependency, attached via configuration, not hardcoded.

The same application can use:

  • Local storage in development
  • Network storage in staging
  • Replicated cloud storage in production

All via the same PVC declaration, just different StorageClasses.