Skip to main content

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