Kubernetes Operations

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
Field note: Pods come and go. Application data needs a lifecycle that is not tied to one disposable Pod.

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.

Field note: The data survived because it belonged to the persistent volume claim, not to the deleted 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
Bottom line: Persistent storage separates data lifecycle from Pod lifecycle. Use claims to request storage and mount that storage into Pods that need durable data.

Check your understanding

  1. Why is container filesystem storage not enough for durable data?
  2. What does a PVC request?
  3. What is a PersistentVolume?
  4. What does a StorageClass define?
  5. What does ReadWriteOnce mean?
  6. What happens to a PVC when a Pod using it is deleted?
  7. What command lists PVCs in a Namespace?
  8. What command lists PersistentVolumes?
  9. Why do StatefulSets matter later for stateful applications?
  10. What are three storage troubleshooting commands?
Answer key
  1. It is tied to the container or Pod lifecycle and can disappear when workloads are replaced.
  2. Storage from the cluster.
  3. A storage resource available to the cluster.
  4. How storage should be provisioned.
  5. The volume can be mounted read-write by one node.
  6. The PVC remains unless it is deleted.
  7. kubectl get pvc -n <namespace>.
  8. kubectl get pv.
  9. They provide stable identity and storage patterns for stateful workloads.
  10. Examples: get pvc, describe pvc, get pv, describe pod, get events.
← Previous: Health Checks Series index Next: Jobs and CronJobs →