Kubernetes Fundamentals · Module 10 of 14

Persistent storage: PVs, PVCs and StorageClasses

Move application data out of ephemeral container filesystems and understand the claim/provision/bind lifecycle used by Kubernetes storage.

Learning objectives

By the end of this module, you should be able to:

  • Distinguish PersistentVolume from PersistentVolumeClaim.
  • Explain dynamic provisioning through a StorageClass.
  • Verify that data survives Pod replacement.

PVCs express workload storage needs

A PersistentVolumeClaim is a namespaced request for storage. A PersistentVolume represents storage capacity made available to the cluster. Binding matches a claim to suitable volume capacity/access characteristics.

StorageClasses enable dynamic provisioning

A StorageClass describes a storage class/provisioner and parameters. When dynamic provisioning is available, creating a PVC can cause a matching PV to be provisioned automatically instead of an administrator creating it first.

Pod replacement and storage lifetime differ

Deleting a Pod does not necessarily delete the PVC/PV. The reclaim behavior is governed by storage objects and policy, not by the container filesystem lifecycle.

Worked examples

See the idea in practice.

Inspect available storage classes

kubectl get storageclass
kubectl -n gnu-k8s-fundamentals get pvc
kubectl get pv
  • StorageClass and PV are cluster-scoped.
  • PVC is namespaced.
Hands-on lab

Lab — Prove PVC persistence

Goal: Create a dynamically provisioned PVC, write data from one Pod, replace the Pod and read the same data.

Before you start

  • kubectl is installed and can reach the lab cluster.
  • Use the dedicated gnu-k8s-fundamentals namespace unless a step explicitly says otherwise.
STEP 1

Create a PVC

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: course-data
  namespace: gnu-k8s-fundamentals
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 100Mi
EOF
STEP 2

Create a writer Pod

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: storage-writer
  namespace: gnu-k8s-fundamentals
spec:
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh","-c","echo persistent-kubernetes > /data/value; sleep 3600"]
    volumeMounts: [{name: data, mountPath: /data}]
  volumes:
  - name: data
    persistentVolumeClaim: {claimName: course-data}
EOF
kubectl -n gnu-k8s-fundamentals wait --for=condition=Ready pod/storage-writer --timeout=120s
STEP 3

Delete only the writer Pod

kubectl -n gnu-k8s-fundamentals delete pod storage-writer --wait=true
STEP 4

Create a reader with the same claim

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: storage-reader
  namespace: gnu-k8s-fundamentals
spec:
  restartPolicy: Never
  containers:
  - name: app
    image: busybox:1.36
    command: ["cat","/data/value"]
    volumeMounts: [{name: data, mountPath: /data}]
  volumes:
  - name: data
    persistentVolumeClaim: {claimName: course-data}
EOF
kubectl -n gnu-k8s-fundamentals wait --for=jsonpath='{.status.phase}'=Succeeded pod/storage-reader --timeout=120s
kubectl -n gnu-k8s-fundamentals logs storage-reader
STEP 5

Clean up

kubectl -n gnu-k8s-fundamentals delete pod storage-reader
kubectl -n gnu-k8s-fundamentals delete pvc course-data

Verify

  • The PVC reaches Bound.
  • The second Pod prints persistent-kubernetes after the first Pod has been deleted.

Expected outcome

  • The data outlives the writer Pod because it lives on the claimed volume.

If it fails

  • If PVC stays Pending, inspect StorageClass availability and events.
  • Access modes describe attachment/access capabilities, not a universal guarantee that all storage backends behave identically.
Real-world connection

Databases, queues and stateful applications require storage lifecycles that are independent of individual Pods.

Avoid these traps

Common mistakes

  • Assuming a PVC is cluster-scoped.
  • Assuming deletion of a Pod always deletes its persistent data.
  • Hard-coding a StorageClass name without checking the target cluster.
Knowledge check

Can you explain it without looking back?

Open each answer only after you have tried to answer the question yourself.

1Which object is the namespaced storage request?

PersistentVolumeClaim.

2What can a StorageClass enable?

Dynamic provisioning of PersistentVolumes through its configured provisioner.

3Why delete/recreate a Pod in a persistence test?

To prove data lifetime is independent of that Pod instance.