Skip to main content

Kubernetes Ep 8: Persistent Volumes, PVCs & StorageClasses

Rachmat Hidayat
Author
Rachmat Hidayat
Learn & sharing insights on TypeScript, Go, Kubernetes, DevOps, DevSecOps, SRE, Platform Engineering, AI/ML Engineering, and MLOps.
kubernetes - This article is part of a series.
Part 8: This Article
Containers are designed to be stateless and ephemeral. To run stateful applications like PostgreSQL, MySQL, Redis, or Elasticsearch, Kubernetes provides storage abstractions that decouple persistent storage infrastructure from application workload definitions.

TL;DR (Quick Summary)
#

  • PersistentVolume (PV): A cluster-wide storage resource provisioned by an administrator or dynamically created by a CSI plugin (AWS EBS, GCP PD, NFS).
  • PersistentVolumeClaim (PVC): A request for storage by a user/Pod (specifying size, access modes, and StorageClass).
  • StorageClass: Enables dynamic provisioning of PVs on-demand when a PVC is submitted.
  • Access Modes:
    • ReadWriteOnce (RWO): Volume can be mounted read-write by a single Node.
    • ReadOnlyMany (ROX): Volume can be mounted read-only by many Nodes.
    • ReadWriteMany (RWX): Volume can be mounted read-write by many Nodes (e.g., NFS, Ceph, EFS).

1. Storage Abstraction Architecture
#


graph TD
    Developer["Developer / Pod Manifest"] -->|Requests 10Gi RWO| PVC["PersistentVolumeClaim (PVC)
(Claim: app-storage-pvc)"] PVC -->|Binds to| PV["PersistentVolume (PV)
(10Gi RWO, Bound)"] SC["StorageClass (gp3 / standard)
(Provisioner: ebs.csi.aws.com)"] -.->|Dynamically Creates| PV PV -->|Mounts underlying storage| Disk["Cloud Disk / Storage LUN
(AWS EBS Volume vol-0a1b2c)"]

2. Dynamic Storage Provisioning with StorageClass
#

In modern Kubernetes clusters, administrators configure a default StorageClass so users don’t have to manually pre-provision static PVs.

Inspect cluster StorageClasses:

kubectl get storageclass

Expected Terminal Output:

NAME                 PROVISIONER                  RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION
standard (default)   k8s.io/minikube-hostpath     Delete          Immediate           true
gp3-csi              ebs.csi.aws.com             Delete          WaitForFirstConsumer true

3. Step-by-Step Stateful Storage Workflow
#

Step 1: Submit a PersistentVolumeClaim (PVC)
#

Create pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-data-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard # Uses cluster default if omitted

Apply PVC:

kubectl apply -f pvc.yaml
kubectl get pvc postgres-data-pvc

Expected Terminal Output:

NAME                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
postgres-data-pvc   Bound    pvc-8d7e9f1a-2b3c-4d5e-6f7a-8b9c0d1e2f3a   5Gi        RWO            standard       12s

Notice how the STATUS instantly changed to Bound because the StorageClass dynamically provisioned a matching PV!


Step 2: Attach PVC to a Pod
#

Create pod-storage.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: postgres-pod
spec:
  containers:
  - name: postgres
    image: postgres:15-alpine
    env:
    - name: POSTGRES_PASSWORD
      value: "SecretDBPass123"
    ports:
    - containerPort: 5432
    volumeMounts:
    - name: postgres-persistent-storage
      mountPath: /var/lib/postgresql/data
  volumes:
  - name: postgres-persistent-storage
    persistentVolumeClaim:
      claimName: postgres-data-pvc

Apply manifest:

kubectl apply -f pod-storage.yaml

4. Reclaim Policies (Retain vs Delete)
#

What happens to the underlying PV and cloud storage disk when a user deletes a PVC?

  • Delete (Default for cloud StorageClasses): Deleting the PVC automatically destroys the bound PV and erases the underlying cloud volume (EBS/GCP PD).
  • Retain: Deleting the PVC leaves the PV intact (Released status). Data on disk is preserved so an administrator can manually recover or re-bind it.

To change reclaim policy on an existing PV:

kubectl patch pv <pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

5. Summary & Next Steps
#

Persistent Volumes ensure your data survives Pod deletions and node crashes. However, deploying databases using a standard Deployment resource can lead to split-brain scenarios or volume attachment errors during node failures.

In Episode 09: StatefulSets & Stateful Database Deployments, we will master StatefulSets to manage stateful workloads requiring unique network identities, ordered deployments, and persistent storage per replica!

kubernetes - This article is part of a series.
Part 8: This Article