PersistentVolumes and PersistentVolumeClaims
PersistentVolumes and claims: the fields that decide whether a claim binds, access modes, reclaim policies, and how to reuse a Released volume.
Key ideas in this lesson · tap one for a simple explanation
What you will be able to do
- Write a hostPath PersistentVolume and a matching claim, mount the claim in a Pod and check that they are bound.
- Read a Pending claim and create exactly the PersistentVolume it needs.
- Explain Retain and Delete, spot a Released volume and make it usable again without losing its data.
Your database needs a disk that survives restarts, and even the deletion of its . A is that disk, and a is how a Pod asks for it. This lesson shows both, and the few fields that must match between them.
The exam asks about them in three ways, and the three tasks at the end practice each one:
- Create a PV, a claim and a Pod that uses the claim.
- Make a waiting (
Pending) claim bind. - Reuse a volume after its claim was deleted.
PV, PVC and StorageClass: three names, three jobs
These three names look alike and are easy to mix up:
Pod
mounts the claim by name
claimName: data-claim
PersistentVolumeClaim
the request: 1Gi, read-write
data-claim
PersistentVolume
the real storage
st-data-pv
The Pod names the claim, and the claim is bound to one PV. The Pod never names the PV.
The PersistentVolume
A PersistentVolume (PV) describes one piece of storage: its size, how it may be used, and where it lives. An admin can create PVs by hand, which is called static provisioning. Or a StorageClass creates them on demand, which is dynamic provisioning (next lesson).
apiVersion: v1
kind: PersistentVolume
metadata:
name: st-data-pv
labels:
tier: data # lets a claim select this PV by label
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: st-manual
hostPath:
path: /opt/st-data
type: DirectoryOrCreateThe fields to know:
capacity.storage: the size. Claims are compared against it.storageClassName: on a PV you make by hand, this is just a name to match. No StorageClass with that name has to exist, but the claim must use the same string.- The source, here
hostPath: where the data really is. Other sources arelocal,nfsandcsi.
A local PV is the stricter cousin of hostPath. It names the one that has the disk, in nodeAffinity. So every Pod that uses it runs on that node.
The PersistentVolumeClaim
A PersistentVolumeClaim (PVC) is a request for storage: a size and an access mode. The app team writes it in the app's namespace. Kubernetes then binds the claim to one PV.
Why the extra step? The Pod names the claim, never the PV. So the same Pod works with a folder on a lab node or a disk in a cloud. Only the PV changes.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-claim
namespace: st-pv
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
storageClassName: st-manual
resources:
requests:
storage: 1Gi
selector:
matchLabels:
tier: dataapiVersion: v1
kind: Pod
metadata:
name: data-pod
namespace: st-pv
spec:
containers:
- name: web
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: data-claimAccess modes
An access mode says how many nodes may mount the volume at once, and whether they may write to it.
- A PV lists every mode it supports. A claim lists the modes it needs, and each one must be on the PV.
- Modes are a matching rule, not a lock. A hostPath PV may say
ReadWriteMany, yet nothing makes two nodes see the same folder. - On the exam, translate the words: "one node" means
ReadWriteOnce, and "many nodes" meansReadWriteMany.
Reclaim policies
The reclaim policy, persistentVolumeReclaimPolicy, decides what happens to a PV when its claim is deleted:
- A PV you create by hand gets
Retainif you leave the field out. A PV made by a StorageClass gets the class's policy, as the next lesson shows. - You can change the policy on a live PV. To keep the data if the claim is deleted:
kubectl patch pv <name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'.
How a claim finds its PV
Kubernetes binds a claim to a PV only when every check below passes. If one fails, the claim stays Pending.
- Size: the PV's
capacity.storageis at least the claim'srequests.storage. Kubernetes picks the smallest PV that fits. So a 1Gi claim may get a 5Gi PV, and then it shows 5Gi. - Access modes: every mode the claim asks for is on the PV.
- Class:
storageClassNameis the same string on both. A claim that leaves it out gets the default class filled in. On this lab that isstandard, which makes a brand-new volume instead of using yours. A claim withstorageClassName: ""binds only to PVs that have no class. - Selector: if the claim has one, the PV's must match it. A claim with a never gets a new volume from a StorageClass.
- Free: the PV is
Available, not bound to another claim. A claim can also ask for one PV by name, withspec.volumeName.
Once bound, the pair stays bound until the claim is deleted. When a claim stays Pending, run kubectl describe pvc <name>. Its events say why. The fix is almost always a PV with the right class, size and access modes.
PV phases and reusing a Released volume
The STATUS column of kubectl get pv shows a PV's phase:
Available
free, waiting for a claim
Bound
in use by one claim
Released
claim deleted, data kept
Available again
after you clear claimRef
claimRef: null
With Delete instead, the PV and its storage are removed when the claim goes, so there is no Released step.
A Released PV still remembers its old claim in spec.claimRef, so no new claim can bind to it. Remove that reference and the PV is free again. The data on it is not touched.
kubectl get pv st-keep-pv # STATUS Released, CLAIM still shows the old claim
kubectl get pv st-keep-pv -o jsonpath='{.spec.claimRef}'
# Drop the reference to the deleted claim. The data on the volume is untouched.
kubectl patch pv st-keep-pv -p '{"spec":{"claimRef":null}}'
# Interactive alternative: kubectl edit pv st-keep-pv and delete the whole claimRef: block.
kubectl get pv st-keep-pv # Available
# A Pending claim that matches is picked up on the controller's next pass (within ~15s).
kubectl -n st-pv wait --for=jsonpath='{.status.phase}'=Bound pvc/keep-claim-v2 --timeout=90sIn the official docs· open on exam day too
- Persistent Volumessearch: persistent volumes
- Volumes: hostPath and localsearch: hostpath volume
- Configure a Pod to Use a PersistentVolume for Storagesearch: configure persistent volume storage
A hostPath PV, a claim and a Pod that mounts it
st-data-pv with 1Gi of capacity, access mode ReadWriteOnce, reclaim policy Retain and storage class name st-manual, backed by the host directory /opt/st-data (create it if it does not exist). In namespace st-pv create a PersistentVolumeClaim named data-claim that requests 1Gi from that volume, and a Pod named data-pod using image nginx:1.27 that mounts the claim at /usr/share/nginx/html. The claim must be Bound to st-data-pv and the Pod must be running.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-1/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-1/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-1/cleanup | bash
Make a Pending claim bind
logs-claim in namespace st-pv has been Pending since it was created. Create a PersistentVolume named st-logs-pv that satisfies it, backed by the host directory /opt/st-logs-pv and with reclaim policy Retain. Do not modify or recreate the claim. When you are done the claim must be Bound to st-logs-pv.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-2/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-2/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-2/cleanup | bash
Reuse a Released Retain volume
st-keep-pv belonged to a claim that has since been deleted. It still holds data that must be kept, and it is now in phase Released. A new claim keep-claim-v2 in namespace st-pv is waiting for it. Make st-keep-pv bindable again so that keep-claim-v2 binds to it. Do not delete or recreate the PersistentVolume, and keep its reclaim policy.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-3/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-3/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/st-pv-3/cleanup | bash
Finished this lesson?
0 of 3 tasks passed. Your readiness counts tasks, so run them before you move on.