In this installment of our Kubernetes blog series, we turn our attention to persistent storage. Unlike ephemeral storage, which is tied to the lifecycle of a pod, persistent storage in Kubernetes allows data to be retained across pod restarts and even node failures. This is crucial for stateful applications like databases. We’ll explore how to implement persistent storage using Persistent Volumes (PVs) and Persistent Volume Claims (PVCs) in a local Kubernetes setup. If you landed here directly, please check out the previous articles in this series:
- Kubernetes Beginner’s Guide Part 1: Introduction
- Kubernetes Beginner’s Guide Part 2: Hello World
- Kubernetes Beginner’s Guide Part 3: Scaling and Managing Workloads
- Kubernetes Beginner’s Guide Part 4: Networking Concepts
Understanding Persistent Volumes (PVs) and Persistent Volume Claims (PVCs)
In Kubernetes, a Persistent Volume (PV) is a piece of storage in the cluster that has been provisioned by an administrator or dynamically provisioned using Storage Classes. A Persistent Volume Claim (PVC) is a request for storage by a user. It is similar to a pod in that pods consume node resources and PVCs consume PV resources.
Creating a Persistent Volume
For this example, we’ll create a local Persistent Volume. In a production environment, you would typically use network-attached storage.
Create a Persistent Volume (PV) YAML File (local-pv.yaml
):
apiVersion: v1 kind: PersistentVolume metadata: name: local-pv spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-storage local: # Use a valid path that exists in your filesystem, below. path: /Users/tvaidyan/Development/k8s-explorations/mnt/data nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - [YourNodeName]
Replace [YourNodeName] with the name of your node. You can get the node name by running kubectl get nodes. Also note the path
specification. Replace the path in my configuration to something that exists on your filesystem. Next, create this persistent volume by applying the yaml configuration, above.
kubectl apply -f local-pv.yaml
Creating a Persistent Volume Claim (PVC)
Next, let’s create a Persistent Volume Claim (PVC). Create a new local-pvc.yaml
file and copy the following configuration into it.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: local-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: local-storage
Apply the PVC configuration:
kubectl apply -f local-pvc.yaml
Utilizing a PVC Within a Pod
Next, let’s create a configuration for creating a pod. We’ll use this new PVC that we created by attaching it to this pod. Create an nginx-pod.yaml
file and copy the following contents.
apiVersion: v1 kind: Pod metadata: name: nginx-pod spec: containers: - name: nginx image: nginx volumeMounts: - mountPath: "/usr/share/nginx/html" name: storage volumes: - name: storage persistentVolumeClaim: claimName: local-pvc
Create the pod by applying the above configuration:
kubectl apply -f nginx-pod.yaml
Verify that the Persistent Volume is bound:
kubectl get pv
You should see that the PV local-pv is bound to the PVC local-pvc. Next, verify that the pod is using this PVC.
kubectl describe pod nginx-pod
Inspect the output, and inspect the Volumes
and the Mounts
sections. Here you can verify that the volume is mounted at the correct path inside the container. This ensures that your pod is utilizing persistent storage as intended.
But does it persist?
The whole objective of this exercise is to create a persistent storage that survives the lifetime of a pod. Pods are ephemeral by nature, susceptible to restarts and deletions. We want to make sure that important data is maintained even in those circumstances.
Let’s experiment by creating a test file in the persistent volume. Exec into the nginx pod:
kubectl exec -it nginx-pod -- /bin/sh
You are now at the bash terminal within your nginx pod. Let’s create a new file, like so:
echo "Hello, persistent storage!" > /usr/share/nginx/html/index.html
Exit the pod:
exit
Simulate a pod failure or deletion:
kubectl delete pod nginx-pod
You can verify that your pod got deleted by issuing the kubectl get pods
command. With the pod deleted, navigate to the directory that you specified in the local-pv.yaml
file above. In my case it was /Users/tvaidyan/Development/k8s-explorations/mnt/data
. You should see an index.html
file there. It should have the phrase “Hello, persistent storage!” within it.
Conclusion
Congratulations! You’ve successfully implemented persistent storage in Kubernetes using Persistent Volumes and Persistent Volume Claims. This setup allows your applications to retain data even if the pods are deleted or moved to a different node. In the next article, we’ll dive deeper into securing your Kubernetes cluster. Stay tuned!