Storage (10%)¶
This domain covers Kubernetes storage concepts including PersistentVolumes, PersistentVolumeClaims, StorageClasses, and various volume types. While only 10% of the exam, storage questions are practical and require understanding the lifecycle of provisioning and consuming persistent storage.
Key Concepts¶
Volume Types¶
Kubernetes supports several volume types. The most commonly tested ones:
| Volume Type | Description | Persistent | Use Case |
|---|---|---|---|
emptyDir | Temporary directory, deleted when pod is removed | No | Scratch space, cache, shared data between containers |
hostPath | Mounts a file or directory from the host node | Yes (node-local) | Single-node testing, accessing host system files |
nfs | NFS share mounted into the pod | Yes | Shared storage across pods and nodes |
persistentVolumeClaim | References a PVC for dynamic/static provisioning | Yes | Production persistent storage |
emptyDir¶
apiVersion: v1
kind: Pod
metadata:
name: shared-data
spec:
containers:
- name: writer
image: busybox
command: ["sh", "-c", "echo 'Hello' > /data/message && sleep 3600"]
volumeMounts:
- name: shared-volume
mountPath: /data
- name: reader
image: busybox
command: ["sh", "-c", "cat /data/message && sleep 3600"]
volumeMounts:
- name: shared-volume
mountPath: /data
volumes:
- name: shared-volume
emptyDir: {}
hostPath¶
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: host-data
mountPath: /usr/share/nginx/html
volumes:
- name: host-data
hostPath:
path: /data/nginx
type: DirectoryOrCreate
hostPath types: DirectoryOrCreate, Directory, FileOrCreate, File, Socket, CharDevice, BlockDevice.
Exam Tip
hostPath volumes are node-specific and not suitable for multi-node production use. They are commonly used in exam questions for simplicity. In production, use PersistentVolumes with a proper storage backend.
PersistentVolumes (PV)¶
A PersistentVolume is a cluster-wide storage resource provisioned by an administrator or dynamically via a StorageClass.
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-data
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data
# NFS PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
server: nfs-server.example.com
path: /exports/data
PersistentVolumeClaims (PVC)¶
A PersistentVolumeClaim is a request for storage by a user. It binds to a matching PV.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual
Using a PVC in a Pod¶
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: persistent-storage
mountPath: /usr/share/nginx/html
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: pvc-data
PV-PVC Binding Rules¶
A PVC binds to a PV when all of the following match:
- Access modes: PV must support the access modes requested by PVC
- Capacity: PV capacity must be >= PVC requested storage
- StorageClass: Must match (or both be empty for no class)
- Selector: If PVC has a selector, PV labels must match
# Check PV and PVC status
kubectl get pv
kubectl get pvc
# Troubleshoot binding issues
kubectl describe pvc pvc-data
Access Modes¶
| Mode | Abbreviation | Description |
|---|---|---|
| ReadWriteOnce | RWO | Mounted as read-write by a single node |
| ReadOnlyMany | ROX | Mounted as read-only by many nodes |
| ReadWriteMany | RWX | Mounted as read-write by many nodes |
| ReadWriteOncePod | RWOP | Mounted as read-write by a single pod (Kubernetes 1.27+) |
Exam Tip
ReadWriteOnce (RWO) means the volume can be mounted by a single node, not a single pod. Multiple pods on the same node can still access a RWO volume.
Reclaim Policies¶
| Policy | Behavior |
|---|---|
| Retain | PV is kept after PVC is deleted. Must be manually reclaimed. |
| Delete | PV and underlying storage are deleted when PVC is deleted. |
| Recycle | Basic scrub (rm -rf /volume/*). Deprecated. |
StorageClasses¶
StorageClasses enable dynamic provisioning of PersistentVolumes. When a PVC references a StorageClass, the provisioner automatically creates a PV.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-storage
provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
# PVC using a StorageClass for dynamic provisioning
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: fast-storage
# List StorageClasses
kubectl get storageclass
# Check the default StorageClass
kubectl get storageclass -o wide
# The default class has the annotation:
# storageclass.kubernetes.io/is-default-class: "true"
Volume Binding Modes¶
- Immediate: PV is provisioned as soon as the PVC is created
- WaitForFirstConsumer: PV provisioning is delayed until a pod using the PVC is scheduled (topology-aware)
Volume Expansion¶
Expanding a PVC requires the StorageClass to have allowVolumeExpansion: true.
# Edit the PVC to request more storage
kubectl edit pvc dynamic-pvc
# Change spec.resources.requests.storage to a larger value
# Or patch it
# kubectl patch pvc dynamic-pvc -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}'
Exam Tip
You can only expand a PVC, never shrink it. The StorageClass must have allowVolumeExpansion: true. Some storage backends require the pod using the PVC to be restarted for the filesystem to be resized.
CSI Drivers¶
The Container Storage Interface (CSI) is the standard for exposing storage systems to Kubernetes. CSI drivers replace in-tree volume plugins.
Common CSI drivers: AWS EBS CSI, GCP PD CSI, Azure Disk CSI, NFS CSI, Longhorn, Rook-Ceph.
Practice Exercises¶
Exercise 1: Create a PV and PVC
Create a PersistentVolume named task-pv with 1Gi capacity, access mode ReadWriteOnce, hostPath /mnt/task-data, and storageClassName manual. Then create a PersistentVolumeClaim named task-pvc that requests 500Mi from this PV.
Solution
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
storageClassName: manual
hostPath:
path: /mnt/task-data
---
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
storageClassName: manual
Exercise 2: Mount a PVC in a Pod
Create a pod named storage-pod using image nginx that mounts the PVC task-pvc from the previous exercise at /usr/share/nginx/html.
Exercise 3: Create a Pod with emptyDir for Sidecar Pattern
Create a pod named sidecar-pod with two containers. The first container (writer) uses image busybox and writes the current date to /var/log/app.log every 5 seconds. The second container (reader) uses image busybox and continuously tails /var/log/app.log. Both containers share an emptyDir volume mounted at /var/log.
Solution
apiVersion: v1
kind: Pod
metadata:
name: sidecar-pod
spec:
containers:
- name: writer
image: busybox
command:
- sh
- -c
- "while true; do date >> /var/log/app.log; sleep 5; done"
volumeMounts:
- name: log-volume
mountPath: /var/log
- name: reader
image: busybox
command:
- sh
- -c
- "tail -f /var/log/app.log"
volumeMounts:
- name: log-volume
mountPath: /var/log
volumes:
- name: log-volume
emptyDir: {}
Exercise 4: Expand a PersistentVolumeClaim
Given an existing PVC named app-data backed by a StorageClass with allowVolumeExpansion: true, expand it from 5Gi to 10Gi.
Solution
# Option 1: Edit directly
kubectl edit pvc app-data
# Change spec.resources.requests.storage from 5Gi to 10Gi
# Option 2: Patch
kubectl patch pvc app-data -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
# Verify
kubectl get pvc app-data
# The CAPACITY column may still show 5Gi until the pod restarts
# Check conditions for resize status
kubectl describe pvc app-data
Exercise 5: Troubleshoot a PVC Stuck in Pending
A PVC named pending-pvc is stuck in Pending status. Identify and fix the issue.
Solution
# Check PVC details
kubectl describe pvc pending-pvc
# Common reasons for Pending PVC:
# 1. No matching PV exists (check access modes, capacity, storageClassName)
kubectl get pv
# 2. StorageClass does not exist or has no provisioner
kubectl get storageclass
# 3. VolumeBindingMode is WaitForFirstConsumer (no pod is using it yet)
kubectl get storageclass -o yaml | grep volumeBindingMode
# Fix depends on the root cause:
# - Create a matching PV if none exists
# - Fix StorageClass name in PVC spec
# - Create a pod that uses the PVC to trigger WaitForFirstConsumer binding
# - Ensure PV access modes and capacity match PVC requirements