Lab 6.2 - PersistentVolumes and PersistentVolumeClaims
Lab Objectives
By the end of this lab, you will be able to:
- Create a PersistentVolume (PV) manually.
- Create a PersistentVolumeClaim (PVC).
- Bind a PVC to a Pod.
- Understand the lifecycle of a PV and a PVC.
- Verify data persistence.
Estimated Duration
45-60 minutes
Prerequisites
- kubectl installed and configured.
- Functional local Kubernetes cluster (minikube or kind).
- Knowledge of PersistentVolumes and PVCs (Chapter 6.2).
Part 1: Creating a PersistentVolume
We will manually create a PersistentVolume. For a local cluster (minikube/kind), we will use a hostPath volume type that mounts a directory from the node.
Step 1.1: Create the PersistentVolume
Create a file pv-example.yaml:
# pv-example.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
labels:
type: local
spec:
storageClassName: manual # StorageClass name (or "" for no class)
capacity:
storage: 1Gi # Volume size
accessModes:
- ReadWriteOnce # RWO: a single node can mount in read-write mode
persistentVolumeReclaimPolicy: Retain # What to do when PVC is deleted: Retain, Delete, Recycle
hostPath:
path: /tmp/k8s-pv-example # Path on the node (for minikube/kind)
type: DirectoryOrCreate # Create the directory if it does not exist
Explanation:
storageClassName: manual: Indicates this PV is manually provisioned (not by a StorageClass).accessModes: ReadWriteOnce: The volume can be mounted in read-write mode by a single node at a time.persistentVolumeReclaimPolicy: Retain: When the PVC is deleted, the PV is retained (data is not deleted).hostPath: For a local cluster, we use a node directory. In production, you would use cloud volumes (EBS, Azure Disk, GCE Persistent Disk) or NFS.
Apply the PersistentVolume:
kubectl apply -f pv-example.yaml
Verify the PV is created:
kubectl get pv pv-example
You should see the PV with status Available (available, not yet bound to a PVC).
Check the details:
kubectl describe pv pv-example
Part 2: Creating a PersistentVolumeClaim
A PVC requests a volume with specific characteristics (size, access mode, StorageClass).
Step 2.1: Create the PersistentVolumeClaim
Create a file pvc-example.yaml:
# pvc-example.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
storageClassName: manual # Must match the PV's storageClassName
accessModes:
- ReadWriteOnce # Must match or be a subset of the PV's accessModes
resources:
requests:
storage: 500Mi # Requests 500 MiB (the PV has 1 GiB, so it works)
Explanation:
storageClassName: manual: The PVC looks for a PV with this StorageClass.accessModes: ReadWriteOnce: The PVC requests a volume with this access mode.resources.requests.storage: 500Mi: The PVC requests at least 500 MiB.
Apply the PersistentVolumeClaim:
kubectl apply -f pvc-example.yaml
Verify the PVC is created and bound to the PV:
kubectl get pvc pvc-example
You should see the PVC with status Bound (bound to the PV).
Verify the PV is now bound:
kubectl get pv pv-example
The status should be Bound and the CLAIM column should show default/pvc-example.
Part 3: Using the PVC in a Pod
Now, we will create a Pod that uses the PVC to store persistent data.
Step 3.1: Create a Pod with the PVC
Create a file pod-with-pvc.yaml:
# pod-with-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-with-pvc
spec:
containers:
- name: app-container
image: busybox
command: ["/bin/sh", "-c"]
args: ["echo 'Persistent data - $(date)' >> /data/persistent-data.txt && cat /data/persistent-data.txt && sleep 3600"]
volumeMounts:
- name: persistent-storage
mountPath: /data # Path where the volume will be mounted in the container
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: pvc-example # Name of the PVC to use
Apply the Pod:
kubectl apply -f pod-with-pvc.yaml
Wait for the Pod to be Running:
kubectl get pods pod-with-pvc
Check the logs to see the written data:
kubectl logs pod-with-pvc
You should see the message with the date.
Step 3.2: Verify Persistence
Delete the Pod:
kubectl delete pod pod-with-pvc
Create a new Pod that reads the data:
# pod-read-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-read-pvc
spec:
containers:
- name: app-container
image: busybox
command: ["/bin/sh", "-c"]
args: ["cat /data/persistent-data.txt && sleep 3600"]
volumeMounts:
- name: persistent-storage
mountPath: /data
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: pvc-example
Apply the new Pod:
kubectl apply -f pod-read-pvc.yaml
Check the logs:
kubectl logs pod-read-pvc
You should see the data written by the first Pod, proving persistence!
Part 4: Cleanup
Delete the created resources:
kubectl delete pod pod-read-pvc
kubectl delete -f pvc-example.yaml
kubectl delete -f pv-example.yaml
Note: With persistentVolumeReclaimPolicy: Retain, even after the PVC is deleted, the PV remains with status Released. The data is preserved. To completely delete the PV, you must delete it manually:
kubectl delete pv pv-example
Lab Summary
In this lab, you explored PersistentVolumes and PersistentVolumeClaims. You learned to manually create a PV, create a PVC that automatically binds to the PV, and use the PVC in a Pod to store persistent data. You also verified that data survives Pod deletion and recreation.
Next Steps
The next lab will introduce you to StorageClasses and dynamic provisioning, which greatly simplify storage management.
Lab 6.3: StorageClasses and Dynamic Provisioning
Lab created: December 2024