Kubernetes Persistent Volumes and Storage

Khimananda Oli 8 min read Virtualization
Kubernetes Persistent Volumes and Storage

By Khimananda Oli | Last reviewed: August 2026

Stateless containers are straightforward, but running databases, message queues, or AI model caches requires reliable data persistence that survives pod restarts and rescheduling. Kubernetes Persistent Volumes and Storage solve this by decoupling storage provisioning from pod lifecycles through an abstraction layer of PersistentVolumes (PVs), PersistentVolumeClaims (PVCs), and StorageClasses. If you are deploying stateful workloads on EKS, AKS, GKE, or bare metal, understanding this binding mechanism is the difference between a resilient system and silent data loss during node failures.

How do Kubernetes Persistent Volumes and Storage actually work?

The core challenge in container orchestration is that pods are ephemeral; when a pod dies, its writable layer vanishes. Kubernetes basics cover deployment, but storage requires a separate mental model. The architecture uses a three-part handshake to decouple infrastructure from application requirements.

PersistentVolume(Cluster Resource)Capacity: 100GiAccess: ReadWriteOncePVC(Namespace Request)Request: 50GiStorageClass: gp3StorageClass(Provisioner Def)Provider: ebs.csi.awsReclaim: DeleteBINDS TOREFERENCES
The binding model for Kubernetes Persistent Volumes and Storage: PVCs bind to compatible PVs defined by StorageClasses

A PersistentVolume (PV) is a cluster-scoped resource representing actual storage (EBS volume, NFS share, Ceph RBD). It has no namespace. A PersistentVolumeClaim (PVC) is a namespace-scoped request for storage by a developer. The StorageClass acts as the blueprint, defining which provisioner creates the underlying storage and with what parameters.

In practice, you rarely create static PVs manually in 2026. Dynamic provisioning is the standard. When a PVC references a StorageClass, the associated CSI driver automatically provisions the backend volume and creates the PV object. This shift-left approach allows platform teams to define guardrails (encryption, IOPS tiers) while developers self-serve storage without opening tickets. For teams exploring self-service infrastructure with Crossplane, this pattern extends beyond native Kubernetes storage to manage external cloud resources declaratively.

How do you configure dynamic provisioning with StorageClasses?

Static provisioning works for legacy NFS or specific compliance needs, but dynamic provisioning reduces operational toil. The key is configuring the StorageClass correctly before any PVCs are created.

Defining a Production-Ready StorageClass

On AWS EKS using the EBS CSI driver, a typical production StorageClass for general-purpose SSD looks like this:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-gp3-encrypted
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
  encrypted: "true"
  kmsKeyId: arn:aws:kms:us-east-1:123456789:key/abcd-1234
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

Three parameters here prevent common production incidents:

  • encrypted: "true": Never store unencrypted data at rest. For SOC 2 or ISO 27001 compliance, encryption must be enforced at the StorageClass level so developers cannot accidentally opt out.
  • allowVolumeExpansion: true: Running out of disk space is inevitable. Without this flag, resizing requires deleting and recreating the PVC. With it, you can patch the PVC spec and the CSI driver handles the filesystem expansion online.
  • volumeBindingMode: WaitForFirstConsumer: This is critical in multi-AZ clusters. Without it, the volume binds immediately upon PVC creation, potentially in an AZ where no node has capacity. Waiting ensures the volume is provisioned in the same AZ as the pod that will consume it.

When managing secrets for KMS keys or database credentials referenced in these configurations, always integrate with secrets management with HashiCorp Vault rather than storing sensitive values directly in manifests or environment variables.

What are the correct access modes for different workloads?

Misconfigured access modes are the most frequent cause of "Multi-Attach error" events in production. The access mode defines how many nodes can mount the volume simultaneously and whether writes are permitted.

Access ModeAbbreviationUse CaseBackend Support
ReadWriteOnceRWODatabases, single-pod apps, logsEBS, Azure Disk, Local Path
ReadOnlyManyROXShared configs, ML model weights, static assetsNFS, EFS, S3 CSI, CephFS
ReadWriteManyRWXShared uploads, CMS media, collaborative editingEFS, Azure Files, NFS, CephFS
ReadWriteOncePodRWOPStrict single-pod write guarantee (k8s 1.29+)EBS, Azure Disk, Local

A common mistake is requesting RWX for a PostgreSQL database because "multiple replicas need access." Block storage (EBS, Azure Disk) does not support RWX. Each replica needs its own RWO PVC. Only file-based systems (NFS, EFS) support true multi-node read-write. If your workload requires shared block storage, you are likely architecting incorrectly; consider object storage (S3) or a proper distributed filesystem instead.

Start: Need StorageMultiple Pods Write Simultaneously?YESNORWX RequiredUse NFS / EFS / CephFSRWO / RWOPUse EBS / Azure DiskFile-Based BackendBlock Backend
Decision flow for choosing access modes in Kubernetes Persistent Volumes and Storage configurations

How do you handle volume lifecycle and reclamation policies safely?

The reclaimPolicy field determines what happens to the underlying storage when the PVC is deleted. Getting this wrong causes either data leaks or catastrophic data loss.

  1. Delete (Default for dynamic): When the PVC is removed, the PV and the physical volume are destroyed. Safe for ephemeral dev/test environments. Dangerous for production databases unless you have verified backups.
  2. Retain: The PVC is unbound, but the PV and physical volume remain. You must manually clean up or rebind. Mandatory for compliance-regulated data where deletion requires approval workflows.

In my experience auditing infrastructure for SOC 2 compliance, I recommend setting Retain for all production StorageClasses and automating cleanup through a separate, audited pipeline. This prevents accidental deletion during namespace cleanup scripts. For teams using GitOps with ArgoCD, ensure your sync policies exclude PV/PVC pruning or require manual confirmation for storage resources.

Handling Volume Expansion in Production

When a database fills up at 3 AM, you need online expansion. Verify your StorageClass supports it:

kubectl get sc ebs-gp3-encrypted -o jsonpath='{.allowVolumeExpansion}'

If true, edit the PVC directly:

kubectl patch pvc postgres-data -p '{"spec":{"resources":{"requests":{"storage":"200Gi"}}}}'

Monitor the resize operation via events. Filesystem expansion happens automatically after the underlying volume grows, but only if the pod is restarted or the CSI driver supports online filesystem expansion (most modern drivers do). Always test expansion procedures in staging first; some older CSI versions require pod recreation.

How do cloud providers differ in Kubernetes storage implementation?

While the Kubernetes API is consistent, the underlying CSI drivers and performance characteristics vary significantly across clouds. Understanding these differences prevents over-provisioning and latency issues.

AWS EKSEBS CSI Drivergp3 / io2 BlockEFS for RWXAZ-Bound (WaitForFirstConsumer)Snapshots: NativeAzure AKSAzure Disk CSIPremium SSD v2Azure Files for RWXZone-Redundant OptionSnapshots: IncrementalGCP GKEPD CSI Driverpd-balanced / pd-extremeFilestore for RWXRegional PD for HASnapshots: Instant
Cloud provider comparison for Kubernetes Persistent Volumes and Storage backends across AWS, Azure, and GCP

On AWS, EBS volumes are AZ-scoped. If you run a StatefulSet across three AZs, each replica gets its own volume in its respective AZ. Cross-AZ mounting fails. For multi-AZ read-write sharing, you must use EFS (NFS-based, higher latency, higher cost). On Azure, Premium SSD v2 offers adjustable IOPS independent of size, which is excellent for cost optimization. GKE's Regional Persistent Disks replicate synchronously across two zones, providing automatic failover without application-level replication — a significant advantage for HA databases.

For Nepal-based teams or startups optimizing costs, remember that storage pricing varies dramatically by tier. gp3 on AWS decouples throughput from storage size, allowing you to provision 100GB with 3000 IOPS without paying for unused capacity. Always benchmark your actual workload before selecting premium tiers; many web applications perform perfectly on balanced storage.

Securing and Optimizing Kubernetes Persistent Volumes and Storage

Storage security is often overlooked in favor of network policies. Apply these hardening steps:

  • Enforce encryption at rest via StorageClass parameters, not per-PVC. Audit regularly with kubectl get sc -o yaml | grep encrypted.
  • Use Pod Security Standards to restrict volume types. Prevent pods from mounting hostPath volumes, which bypass PVC controls entirely.
  • Implement quota limits per namespace to prevent runaway storage consumption: kubectl create quota storage-limit --hard=persistentvolumeclaims=10,requests.storage=500Gi.
  • Monitor usage with kube-state-metrics. Alert at 80% capacity; automated expansion should trigger at 85%. Integrate alerts into your Prometheus and Grafana setup for visibility.

Performance tuning matters equally. For high-IOPS workloads, use dedicated StorageClasses with pre-configured IOPS/throughput parameters rather than relying on defaults. Test with fio inside a pod before production deployment. Remember that CSI drivers add overhead; ensure your nodes have sufficient CPU/memory for the driver DaemonSets, especially on smaller instance types common in cost-sensitive deployments.

Next Steps for Reliable Stateful Workloads

Mastering Kubernetes Persistent Volumes and Storage transforms stateful deployments from fragile experiments into production-grade systems. Start by auditing your existing StorageClasses for encryption, expansion support, and appropriate reclaim policies. Migrate static PVs to dynamic provisioning where possible. Test failure scenarios: delete a PVC, simulate AZ failure, verify backup restoration. Storage is where abstract cloud promises meet physical reality; treat it with the same rigor as your compute layer.

If your team needs help designing compliant, cost-efficient storage architectures for Kubernetes — whether on AWS, Azure, GKE, or hybrid infrastructure in Nepal — reach out to discuss your specific requirements. I help organizations build storage foundations that pass audits and survive traffic spikes without 3 AM pages.

Frequently Asked Questions

A PersistentVolume is a cluster resource provisioned by an admin or dynamically, while a PersistentVolumeClaim is a user request for storage. The claim binds to a matching volume based on size, access modes, and storage class, decoupling storage provisioning from pod consumption in Kubernetes Persistent Volumes and Storage workflows.

Define a StorageClass with a provisioner like ebs.csi.aws.com or pd.csi.storage.gke.io. Set volumeBindingMode to WaitForFirstConsumer to delay binding until pod scheduling. Ensure the CSI driver is installed and RBAC permissions allow volume creation. This automates Kubernetes Persistent Volumes and Storage allocation without manual PV objects.

ReadWriteOnce allows single-node read-write access. ReadOnlyMany permits multi-node read-only mounts. ReadWriteMany enables concurrent read-write from multiple nodes but requires specific storage backends like NFS or Ceph. ReadWriteOncePod restricts access to a single pod. Always verify backend support before specifying access modes in your PersistentVolumeClaim.

Yes, if the StorageClass has allowVolumeExpansion set to true and the underlying CSI driver supports it. Edit the PersistentVolumeClaim spec to increase storage.request. The filesystem expands automatically when the pod restarts or via online expansion if supported. Check driver documentation for Kubernetes Persistent Volumes and Storage resize limitations.

It depends on the reclaimPolicy in the bound StorageClass or PersistentVolume. Delete policy removes both the claim and underlying storage asset immediately. Retain policy keeps the physical volume intact for manual recovery but marks the PV as Released. Always configure retention carefully for production Kubernetes Persistent Volumes and Storage to prevent accidental data loss.

Run kubectl describe pvc to check events for binding failures. Verify available PVs match requested size, access modes, and storageClassName. Confirm the CSI driver pods are running and healthy. Check node affinity labels if using WaitForFirstConsumer. These steps resolve most Kubernetes Persistent Volumes and Storage provisioning issues.

No, encryption depends entirely on the underlying storage provider and CSI driver configuration. AWS EBS and GCP PD offer default encryption, but NFS or local-path-provisioner typically do not. Enable encryption parameters in your StorageClass or cloud provider settings. Always audit Kubernetes Persistent Volumes and Storage encryption compliance for sensitive workloads.

Avoid hostPath in production because data ties to specific nodes and lacks lifecycle management. Use it only for development or node-level agents. Production workloads require network-attached or dynamically provisioned Kubernetes Persistent Volumes and Storage to ensure portability, backups, and proper reclaim policies across cluster upgrades and node failures.

Use Velero with CSI snapshot support or cloud-native tools like AWS Backup for EBS snapshots. Schedule regular backups via CronJobs or external orchestrators. Test restore procedures quarterly. Application-consistent backups require quiescing databases before snapshotting. Never rely solely on replication for disaster recovery in Kubernetes Persistent Volumes and Storage environments.

Cloud-managed CSI drivers like EBS, Azure Files, or GCP Filestore suit most teams. On-premises clusters benefit from Rook-Ceph or Longhorn for distributed storage. Evaluate latency, throughput, access mode needs, and operational overhead. Benchmark real workloads before committing to a Kubernetes Persistent Volumes and Storage backend for production deployments.

Spin up a temporary pod mounting both source and destination PVCs. Use rsync or rclone to copy data while validating checksums. Quiesce write operations during transfer to ensure consistency. Update deployment manifests to reference the new claim after verification. This approach minimizes downtime for Kubernetes Persistent Volumes and Storage migrations.

The container user ID lacks ownership of the mounted path. Set fsGroup in pod securityContext to apply group permissions recursively. Alternatively, use init containers to chown the volume before app startup. Some CSI drivers support mountOptions for UID/GID mapping. Fix permission issues systematically in Kubernetes Persistent Volumes and Storage configurations.

Only if the PV supports ReadWriteMany access mode and uses a compatible backend like NFS, CephFS, or EFS. Block storage like EBS or GCE-PD typically allows single-writer access. Concurrent writes to unsupported volumes cause corruption. Validate backend capabilities before designing shared-state architectures with Kubernetes Persistent Volumes and Storage.

Deploy kube-state-metrics and node-exporter to expose volume capacity and inode metrics. Create Prometheus alerts for usage exceeding eighty percent. Use kubectl top pv or cloud dashboards for real-time inspection. Integrate Grafana dashboards tracking PVC utilization trends. Proactive monitoring prevents outages caused by exhausted Kubernetes Persistent Volumes and Storage resources.

Yes.