Persistent Storage: Volumes and Claims
Pods are disposable, but some data needs to survive. Persistent storage separates the lifecycle of application data from the lifecycle of any one Pod.
What this lesson covers
Containers are disposable, but some applications need data that survives Pod replacement. Kubernetes supports storage through volumes, PersistentVolumes, PersistentVolumeClaims, and StorageClasses.
- Why container filesystems are temporary
- What a volume is
- What PersistentVolumes and PersistentVolumeClaims are
- How a StorageClass helps dynamically provision storage
- How to mount persistent storage into a Pod
- How to prove data survives Pod recreation
- How to clean up storage safely
The short version
Volume: Storage mounted into a Pod. PersistentVolume: A piece of storage available to the cluster. PersistentVolumeClaim: A request for storage by a workload. StorageClass: Defines how storage should be provisioned.
Why Pod storage is not enough
A container can write files to its own filesystem, but that filesystem belongs to the container lifecycle. When the container is replaced, those files can disappear.
That is fine for stateless web servers. It is not fine for databases, uploads, queues, or applications that must keep durable state.
Before you start the lab
kubectl config current-context kubectl get nodes kubectl get storageclass
In kind, you will commonly see a local storage class such as standard or local-path, depending on cluster configuration.
Step 1: Create a Namespace
kubectl create namespace storage-lab
Step 2: Create a PersistentVolumeClaim
Create a file named:
pvc-lab.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc-lab
namespace: storage-lab
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
kubectl apply -f pvc-lab.yaml kubectl get pvc -n storage-lab
Step 3: Create a Pod that writes to the PVC
Create a file named:
pvc-writer-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pvc-writer-pod
namespace: storage-lab
spec:
containers:
- name: writer
image: busybox:latest
command: ["sh", "-c", "echo persistent-data-from-first-pod > /data/message.txt; sleep 3600"]
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-pvc-lab
kubectl apply -f pvc-writer-pod.yaml kubectl get pods -n storage-lab kubectl logs pvc-writer-pod -n storage-lab
Step 4: Inspect the file
kubectl exec -it pvc-writer-pod -n storage-lab -- /bin/sh cat /data/message.txt exit
Step 5: Delete the first Pod
kubectl delete pod pvc-writer-pod -n storage-lab kubectl get pods -n storage-lab kubectl get pvc -n storage-lab
The Pod is gone, but the claim remains.
Step 6: Create a second Pod that reads the same PVC
Create a file named:
pvc-reader-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pvc-reader-pod
namespace: storage-lab
spec:
containers:
- name: reader
image: busybox:latest
command: ["sh", "-c", "cat /data/message.txt; sleep 3600"]
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-pvc-lab
kubectl apply -f pvc-reader-pod.yaml kubectl logs pvc-reader-pod -n storage-lab
You should see the message written by the first Pod.
Step 7: Inspect the bound volume
kubectl get pvc -n storage-lab kubectl describe pvc data-pvc-lab -n storage-lab kubectl get pv
Step 8: Create a Deployment using a PVC
Create a file named:
pvc-deployment-lab.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pvc-deployment-lab
namespace: storage-lab
spec:
replicas: 1
selector:
matchLabels:
app: pvc-deployment-lab
template:
metadata:
labels:
app: pvc-deployment-lab
spec:
containers:
- name: app
image: busybox:latest
command: ["sh", "-c", "while true; do date >> /data/timestamps.txt; sleep 10; done"]
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-pvc-lab
kubectl apply -f pvc-deployment-lab.yaml kubectl get pods -n storage-lab
Step 9: Restart the Deployment Pod
kubectl get pods -n storage-lab kubectl delete pod <deployment-pod-name> -n storage-lab kubectl get pods -n storage-lab
The Deployment creates a replacement Pod. The replacement Pod mounts the same claim.
Step 10: Inspect data after replacement
kubectl exec -it <new-deployment-pod-name> -n storage-lab -- /bin/sh tail /data/timestamps.txt cat /data/message.txt exit
Access modes
Access modes describe how storage can be mounted:
- ReadWriteOnce: Mounted read-write by one node.
- ReadOnlyMany: Mounted read-only by many nodes.
- ReadWriteMany: Mounted read-write by many nodes, if the storage provider supports it.
- ReadWriteOncePod: Mounted read-write by a single Pod where supported.
Common storage troubleshooting commands
kubectl get pvc -n <namespace> kubectl describe pvc <pvc-name> -n <namespace> kubectl get pv kubectl describe pv <pv-name> kubectl get storageclass kubectl describe pod <pod-name> -n <namespace> kubectl get events -n <namespace> --sort-by=.metadata.creationTimestamp
Step 11: Clean up
kubectl delete -f pvc-deployment-lab.yaml kubectl delete -f pvc-reader-pod.yaml kubectl delete -f pvc-lab.yaml kubectl delete namespace storage-lab
Check your understanding
- Why is container filesystem storage not enough for durable data?
- What does a PVC request?
- What is a PersistentVolume?
- What does a StorageClass define?
- What does ReadWriteOnce mean?
- What happens to a PVC when a Pod using it is deleted?
- What command lists PVCs in a Namespace?
- What command lists PersistentVolumes?
- Why do StatefulSets matter later for stateful applications?
- What are three storage troubleshooting commands?
Answer key
- It is tied to the container or Pod lifecycle and can disappear when workloads are replaced.
- Storage from the cluster.
- A storage resource available to the cluster.
- How storage should be provisioned.
- The volume can be mounted read-write by one node.
- The PVC remains unless it is deleted.
- kubectl get pvc -n <namespace>.
- kubectl get pv.
- They provide stable identity and storage patterns for stateful workloads.
- Examples: get pvc, describe pvc, get pv, describe pod, get events.