CKA — Persistent Volume Claims
CKA Exam Domain
Storage — 10%
PersistentVolumeClaims are how users request storage in Kubernetes. On the CKA exam, you need to create PVCs, understand how binding works, and mount them in Pods — all from memory.
What Is a PVC?
A PersistentVolumeClaim (PVC) is a user’s request for storage. Think of it as a “storage ticket” — you specify how much storage you need and what access mode you require, and Kubernetes finds a matching PV to bind to.
Key points:
- PVCs are namespaced (unlike PVs which are cluster-scoped)
- A PVC binds to exactly one PV (1:1 relationship)
- Once bound, the PVC exclusively owns that PV — no other PVC can use it
- Pods reference PVCs, not PVs directly
PVC Spec
Here is a complete PVC definition:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
storageClassName: manual
Key fields:
| Field | Description |
|---|---|
accessModes |
How the volume should be mounted (must match or be a subset of the PV’s access modes) |
resources.requests.storage |
Minimum amount of storage needed |
storageClassName |
Must match the PV’s storageClassName for binding |
Exam tip: If the PVC’s
storageClassNamedoes not match the PV’sstorageClassName, binding will not happen — even if capacity and access modes match. This is a common gotcha.
How Binding Works
When you create a PVC, Kubernetes looks for a PV that satisfies all of the following:
- storageClassName — Must match exactly
- accessModes — PV must support the requested access mode(s)
- capacity — PV capacity must be greater than or equal to the requested amount
The binding process:
PVC created → Scheduler looks for matching PV → PV found → Bound (1:1)
→ No match → PVC stays Pending
Important details:
- Binding is 1:1 — one PVC binds to one PV
- If a PVC requests 3Gi and the only available PV has 10Gi, it will bind (but the remaining 7Gi is wasted)
- If no PV matches, the PVC stays in
Pendingstate until a suitable PV becomes available
Claim Selectors
You can use matchLabels in a PVC to target a specific PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-fast
labels:
type: ssd
environment: production
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: manual
hostPath:
path: /data/fast
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-fast
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual
selector:
matchLabels:
type: ssd
environment: production
This PVC will only bind to a PV that has both labels type: ssd and environment: production.
Using PVCs in Pods
Once a PVC is bound, you reference it in a Pod spec:
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: nginx
volumeMounts:
- mountPath: /data
name: storage
volumes:
- name: storage
persistentVolumeClaim:
claimName: pvc-demo
The flow:
Pod spec → volumes[].persistentVolumeClaim.claimName → PVC → PV → Actual storage
Exam tip: The
volumes[].namefield must match thevolumeMounts[].namefield in the container. This is a common mistake under exam pressure.
Full End-to-End Example
Here is PV + PVC + Pod together:
# 1. PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-demo
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /data/pv-demo
---
# 2. PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
storageClassName: manual
---
# 3. Pod
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
spec:
containers:
- name: app
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: web-storage
volumes:
- name: web-storage
persistentVolumeClaim:
claimName: pvc-demo
PVC Protection
Kubernetes has Storage Object in Use Protection enabled by default. This prevents accidental deletion of PVCs that are actively used by Pods.
How it works:
- When a PVC is in use by a Pod, Kubernetes adds a finalizer:
kubernetes.io/pvc-protection - If you try to
kubectl delete pvc, the PVC enters aTerminatingstate but is not actually deleted - Once all Pods using the PVC are deleted, the PVC is removed
You can verify the finalizer:
kubectl get pvc pvc-demo -o yaml | grep -A 2 finalizers
kubectl Commands
Essential PVC commands for the exam:
# List all PVCs in the current namespace
kubectl get pvc
# List PVCs in all namespaces
kubectl get pvc -A
# Describe a PVC for detailed information
kubectl describe pvc pvc-demo
# Delete a PVC
kubectl delete pvc pvc-demo
# Check PVC in YAML format
kubectl get pvc pvc-demo -o yaml
Expected output of kubectl get pvc:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo Bound pv-demo 5Gi RWO manual 30s
Practice Questions
Q1. Create a PVC named claim-log that requests 50Mi of storage with ReadWriteOnce access mode and storageClassName manual.
Show Answer
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: claim-log
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Mi
storageClassName: manual
kubectl apply -f claim-log.yaml
kubectl get pvc claim-log
Q2. A PVC is stuck in Pending state. What are the possible reasons?
Show Answer
Common reasons:
- No matching PV — No PV with matching storageClassName, accessModes, or sufficient capacity
- StorageClass does not exist — The referenced StorageClass has not been created
- volumeBindingMode: WaitForFirstConsumer — The PV will not bind until a Pod using this PVC is scheduled
- All matching PVs are already bound — PV binding is 1:1
Debug with:
kubectl describe pvc <pvc-name>
# Check the Events section for clues
Q3. Create a Pod named web-pod using image nginx that mounts a PVC called web-pvc at /usr/share/nginx/html.
Show Answer
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: web-storage
volumes:
- name: web-storage
persistentVolumeClaim:
claimName: web-pvc
Q4. What happens if you delete a PVC that is currently in use by a running Pod?
Show Answer
The PVC enters a Terminating state but is not actually deleted. Kubernetes Storage Object in Use Protection (via the kubernetes.io/pvc-protection finalizer) prevents deletion until all Pods using the PVC are removed.
Once the Pod is deleted, the PVC will be fully removed.
Q5. A PVC requests 2Gi storage but the only available PV has 10Gi. Will the PVC bind? What happens to the extra 8Gi?
Show Answer
Yes, the PVC will bind to the 10Gi PV (assuming storageClassName and accessModes match). The PV capacity must be greater than or equal to the PVC request.
The extra 8Gi is effectively wasted — no other PVC can bind to this PV because PV-to-PVC binding is 1:1. This is one reason dynamic provisioning with StorageClasses is preferred, as it creates a PV with exactly the requested size.