1. PV & PVC Lifecycle
Static Provisioning:
Admin creates PV → Developer creates PVC → K8s binds PVC to matching PV
Dynamic Provisioning:
Developer creates PVC (with storageClassName) → StorageClass auto-creates PV
Binding criteria:
✓ accessMode match
✓ storage size: PV >= PVC requested
✓ storageClass match (or "")
✓ volumeMode match
2. Creating PV and PVC
# PersistentVolume (static, hostPath for lab)
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-data
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data # Lab only; use NFS/EBS in production
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: manual
| Reclaim Policy | Behavior when PVC is deleted |
|---|---|
| Retain | PV keeps data, phase = Released (admin must delete manually) |
| Delete | PV and storage backend are deleted automatically |
| Recycle (deprecated) | Deletes files, PV ready for new PVC |
Exam tip: PV phase lifecycle: Available (no PVC) → Bound (PVC bound) → Released (PVC deleted, Retain policy) → Failed. A Released PV cannot bind to a new PVC until the admin manually edits the PV to remove
.spec.claimRef.
3. StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
annotations:
storageclass.kubernetes.io/is-default-class: "true" # Default SC
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iopsPerGB: "10"
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer # Delay until Pod scheduled
| volumeBindingMode | Behavior |
|---|---|
| Immediate | PV provisioned immediately when PVC is created |
| WaitForFirstConsumer | Delayed until Pod is scheduled (ensures same zone) |
4. Pod Using PVC
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: data-volume
mountPath: /var/data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: pvc-data # Reference PVC name
5. Cheat Sheet
| Task | Command |
|---|---|
| List PVs | kubectl get pv |
| List PVCs | kubectl get pvc -n NAMESPACE |
| PVC status | kubectl describe pvc NAME |
| List StorageClasses | kubectl get storageclass |
| Expand PVC | Edit PVC spec.resources.requests.storage (SC must allow) |
6. Practice Questions
Q1: A PVC is stuck in "Pending" state. A PV with 10Gi exists. The PVC requests 5Gi with ReadWriteMany, but the PV only supports ReadWriteOnce. What happens?
- A) The PVC binds to the PV and uses RWO
- B) The PVC remains Pending — no PV matches the requested access mode ✓
- C) Kubernetes auto-converts the PV access mode
- D) The Pod using the PVC starts but cannot write
Explanation: PVC binding requires all criteria to match: storage size (PV >= PVC), access mode, storageClass, and volumeMode. If the PV only supports RWO but PVC needs RWX, they won't bind.
Q2: A PVC bound to a PV is deleted. The PV has reclaimPolicy: Retain. What is the PV's state?
- A) The PV is deleted
- B) The PV transitions to Available and can be reused
- C) The PV transitions to Released — data is preserved but PV can't be rebound automatically ✓
- D) The PV is immediately provisioned for another PVC
Explanation: Retain policy preserves the PV and its data. The PV enters Released state. To reuse it, an admin must manually delete the old claimRef (kubectl patch pv myPV -p '{"spec":{"claimRef":null}}') to return it to Available.
Q3: In a cloud environment, WaitForFirstConsumer volumeBindingMode is recommended over Immediate. Why?
- A) It reduces storage costs
- B) It ensures the volume is provisioned in the same availability zone as the scheduled Pod ✓
- C) It allows multiple Pods to share the volume
- D) It speeds up Pod startup time
Explanation: With Immediate, the PV might be provisioned in zone-a while the Pod schedules to zone-b (EBS volumes are zone-specific). WaitForFirstConsumer delays provisioning until the scheduler determines which node/zone will host the Pod.