Persistent storage in Kubernetes starts with a claim that asks the cluster for a volume instead of tying a Pod to a node-local path. A PersistentVolumeClaim lets a workload request capacity and access mode from a StorageClass so application data can survive container restarts and Pod replacement.
PersistentVolumeClaim objects are namespaced. The StorageClass controls how a matching PersistentVolume is provisioned, and some classes wait until a Pod consumes the claim before binding the volume to a node.
A small lab namespace, a 1 GiB ReadWriteOnce claim, and a test Pod that writes a file through the mounted volume prove both binding and real use. Replace standard with the StorageClass used by your cluster, then keep the claim in place for real workloads instead of running the lab cleanup.
Steps to create a Kubernetes PersistentVolumeClaim:
- List the available StorageClasses.
$ kubectl get storageclass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE standard (default) rancher.io/local-path Delete WaitForFirstConsumer false 3m28s
The PVC manifest selects standard. A class with WaitForFirstConsumer can leave the claim Pending until a Pod that uses it is scheduled.
- Create a namespace for the PVC test.
$ kubectl create namespace storage-demo namespace/storage-demo created
Use the target application namespace instead of storage-demo when creating a real claim.
Related: How to create a Kubernetes namespace
- Save the PersistentVolumeClaim manifest.
- app-data-pvc.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: app-data spec: accessModes: - ReadWriteOnce storageClassName: standard resources: requests: storage: 1Gi
ReadWriteOnce allows the volume to be mounted read-write by workloads on one node at a time. Change storageClassName to the class that should provision the volume in your cluster.
- Apply the claim to the namespace.
$ kubectl apply -f app-data-pvc.yaml --namespace storage-demo persistentvolumeclaim/app-data created
- Check the initial claim phase.
$ kubectl get pvc app-data --namespace storage-demo NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE app-data Pending standard <unset> 0s
Pending is expected here when the selected StorageClass uses WaitForFirstConsumer. Classes with immediate binding may show Bound before a Pod exists.
- Save a test Pod manifest that mounts the claim.
- pvc-writer-pod.yaml
apiVersion: v1 kind: Pod metadata: name: pvc-writer spec: restartPolicy: Never containers: - name: writer image: busybox:1.36 command: ["sh", "-c", "echo pvc-ok > /data/check.txt; sleep 300"] volumeMounts: - name: app-data mountPath: /data volumes: - name: app-data persistentVolumeClaim: claimName: app-data
The container writes one file to the mounted volume and stays running long enough for the readback check.
- Create the test Pod in the same namespace.
$ kubectl apply -f pvc-writer-pod.yaml --namespace storage-demo pod/pvc-writer created
- Wait for the Pod to become ready.
$ kubectl wait --for=condition=Ready pod/pvc-writer --namespace storage-demo --timeout=120s pod/pvc-writer condition met
- Wait for the claim to bind.
$ kubectl wait --for=jsonpath='{.status.phase}'=Bound pvc/app-data --namespace storage-demo --timeout=90s persistentvolumeclaim/app-data condition metThe Bound phase means the claim has been matched with a PersistentVolume.
- Read the file written through the mounted claim.
$ kubectl exec pvc-writer --namespace storage-demo -- cat /data/check.txt pvc-ok
- Inspect the bound claim.
$ kubectl get pvc app-data --namespace storage-demo NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE app-data Bound pvc-ae56be57-ff92-4c43-96b4-454eed635cd6 1Gi RWO standard <unset> 7s
- Delete the temporary test Pod when the claim should stay available.
$ kubectl delete pod pvc-writer --namespace storage-demo pod "pvc-writer" deleted from storage-demo namespace
- Delete the lab namespace only when all test resources should be removed.
$ kubectl delete namespace storage-demo namespace "storage-demo" deleted
Skip this command for a real application namespace. Deleting the namespace also removes the PersistentVolumeClaim and the dynamically provisioned volume.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.