\ ## **What Are Kubernetes Persistent Volumes?** Ordinarily, containers in a Kubernetes cluster are immutable. This means that when you shut down a container, any information stored within it is lost. This is suitable for stateless applications, but in order to run stateful applications like databases in Kubernetes, you will need persistent storage. \ To enable persistent storage that survives the shutdown of a container or pod, Kubernetes provides a persistent volumes subsystem. It provides API objects to let you allocate and manage storage resources persistently. \n You can set up persistent storage using the following API resources: \n * **PersistentVolume (PVs)**—each PV represents a storage resource available within the cluster. Unlike ephemeral volumes, the lifecycle of a PV is independent of any pod using it. This ensures that the storage remains persistent. Administrators can provision PVs manually. Kubernetes can also dynamically provision PVs using storage classes. * **PersistentVolumeClaims (PVCs)**—each PVC represents a request for storage. A PVC can consume only a PV resource that meets its size and access modes requirements. If a relevant PV is available, it is bound to the PVC. Otherwise, Kubernetes dynamically provisions a PV or the request fails. \ For more background see this __[blog about Kubernetes Persistent Volumes](https://cloud.netapp.com/blog/kubernetes-persistent-storage-why-where-and-how)__. ## Kubernetes Storage Concepts ### Kubernetes Storage Class Kubernetes lets administrators define __[StorageClasses](https://kubernetes.io/docs/concepts/storage/storage-classes/)__ that are abstracted from the storage implementation. It enables users to request the specific StorageClass relevant to each PVC without specifying all storage requirements. \ Administrators can create various types of StorageClasses, each defined differently for the provisioner, parameters, and reclaimPolicy. It lets you set up StorageClasses that provide different performance, such as HDD or SSD, costs, and applications. The provisioner lets you tie a StorageClass to specific backends, such as AWS EBS or Azure Files, and a storage endpoint. Additional parameters are available according to the chosen provisioner to help you describe the volumes for each StorageClass using parameters like `type`, `zone`, `server`, or `path`. ### Kubernetes StatefulSet A __[Kubernetes StatefulSet](https://spot.io/resources/kubernetes-architecture/kubernetes-statefulsets-scaling-managing-persistent-apps/)__ is a workload API object for managing stateful applications. It lets you define a set of pods with unique network identifiers to be deployed and scaled in a specific order. StatefulSets help manage persistent storage across a Kubernetes cluster. \ Pods associated with a StatefulSet are assigned a unique identity comprised of stable storage, an ordinal, and a stable network identity. This identifier sticks to the pods and the StatefulSet maintains it across scheduling and rescheduling. Learn more in this __[blog about Kubernetes networking](https://www.tigera.io/learn/guides/kubernetes-networking/)__. ### Kubernetes CSI Plugins Container Storage Interface (CSI) plugins help make third-party storage available for your Kubernetes cluster. It helps introduce persistent storage to containerized applications. CSI plugins receive PVC requests that specify the third-party vendor as a provisioner and then create and mount the requested volume. ## Lifecycle of PVs and PVCs A PVC is a request for a PV that exists as a storage resource within a Kubernetes cluster. A PVC is tied to a matching PV to ensure storage remains persistent. As a result, the lifecycle of PVs and PVCs is usually tightly connected. ### Provisioning Kubernetes provides the following types of provisioning for persistent storage: \ * **Static**—this type of provisioning is available for cluster administrators. It enables admins to manually create PV resources and make them available to all cluster users. Once the PV exists within the Kubernetes API, users can create a PVC request for a pod to consume a PV resource. * **Dynamic**—this type of provisioning is available for a Kubernetes cluster. It enables the cluster to automatically provision a PV to match a PVC according to predefined StorageClasses. Dynamic provisioning typically occurs when non of the PVs statically provisioned match a PVC. ### Binding A control loop monitors new PVCs. Once a user creates a new PVC, the control loop searches for a marching PV that meets the PVC requirements. It looks to satisfy the requested amount of storage and may do so using a PV that exceeds the request. Here is how this process works: \ * If the control loop finds a matching PV, it binds it to the PVC. Binding ensures that the PV and PVC remain exclusive. * If the control loop cannot find a PV that meets the PVC requirements for access mode and storage size, it dynamically provisions a new PV according to the StorageClass and binds it to the PVC. * If no PV is available for a PVC—static or dynamic—the PVC remains unbound indefinitely. ### Using Kubernetes pods use PVCs as volumes. Users can specify an access mode for the PVC, and the cluster mounts the bound PV to the pod. When using volumes that support multiple access modes, the user must specify the desired mode. Once a user gets a bound PVC, the bound PV also belongs to that user. ### Reclaiming Once a user no longer needs to use a volume, it can be deleted or retained. Users can delete a PVC object directly from the API that enables them to reclaim this resource. Otherwise, the PV’s reclaim policy defines what the cluster should do with a volume that was released of its claim. ## Quick Tutorial: Working with Persistent Volumes This tutorial is adapted from the full persistent storage tutorial in the __[Kubernetes documentation](https://minikube.sigs.k8s.io/docs/)__. \ Before starting this tutorial, set up a Kubernetes cluster on your local machine with only one node. Ensure that kubectl is installed on your machine and communicating successfully with the cluster. You can easily create a one-node cluster with __[Minikube](https://minikube.sigs.k8s.io/docs/)__. ### Step 1: Create a File On the Node Because we are working with persistent storage, we need to create a static file and demonstrate that this file persists even after we shut down a node. \ Open a shell to your node, create a directory named `/mnt/data`, and inside it create an `index.html` file with the text “Hello World Persistent Volume”. ### Step 2: Create a Persistent Volume To create a persistent volume, open a text editor and copy-paste the YAML code below. \ `apiVersion: v1` `kind: PersistentVolume` `metadata:` ` name: my-pv-volume` ` labels:` ` type: local` `spec:` ` storageClassName: manual` ` capacity:` ` storage: 6Gi` ` accessModes:` ` —ReadWriteOnce` ` hostPath:` ` path: "/mnt/data"` \ Save the YAML file as `my-pv-volume.yaml`in your local directory. Deploy the persistent volume by running this command: \n `kubectl create -f my-pv-volume.yaml` ### Step 3: Create a Persistent Volume Claim Create a PVC specification by opening your text editor and copying the YAML code below: \ `apiVersion: v1` `kind: PersistentVolumeClaim` `metadata:` ` name: my-pv-claim` `spec:` ` storageClassName: manual` ` accessModes:` ` —ReadWriteOnce` ` resources:` ` requests:` ` storage: 2Gi` \ Save the file in your local directory as `my-pv-claim.yaml`. Deploy it using this command:\*\* \n `kubectl apply -f my-pv-claim.yaml` ### Step 4: Create a Pod and Mount the PVC as a Volume Now it gets interesting—let’s create a pod that mounts this PVC so it can make use of our persistent volume. Copy the following code to your text editor: \ `apiVersion: v1` `kind: Pod` `metadata:` ` name: my-pv-pod` `spec:` ` volumes:` ` —name: my-pv-storage` ` persistentVolumeClaim:` ` claimName: my-pv-claim` ` containers:` ` —name: my-pv-container` ` image: nginx` ` ports:` ` —containerPort: 80` ` name: "http-server"` ` volumeMounts:` ` —mountPath: "/usr/share/nginx/html"` ` name: my-pv-storage` \ Notice that the pod specifies the PVC, it does not directly reference the PV. Kubernetes is responsible for matching this pod with a PV that meets its requirements, based on the information in the PVC. In our case it is simple because there is only one PV. \ Save the pod spec in your local directory as `my-pv-pod.yaml`. Deploy the pod by running this command: \ `kubectl apply -f my-pv-pod.yaml` \ Ensure the pod is running: \ `kubectl get pod my-pv-pod` ### Step 5: Verify that the Pod Has Access to Persistent Storage Let’s see if our pod can access the file we saved in persistent storage at the beginning of the tutorial. The important thing here is that **any** pod you create using this specification will have access to the same storage—even after you shut down or delete the pod, the file will persist. \ Run this command to bash into the container: \ `kubectl exec -it my-pv-pod -- /bin/bash` \n Once you are running in the root shell of your container, run these commands: \ `apt update` `apt install curl` `curl http://localhost/` \ You should see the content of your index.html files: \ `Hello World Persistent Volume` \n Congrats! You just created a pod that has access to a Persistent Volume via a Persistent Volume Claim. ## Conclusion In this article, I explained the basics of Kubernetes persistent storage, explained the concepts of Persistent Volumes and Persistent Volume Claims, and showed how to set up a quick demo of a pod that mounts a PVC: \ 1\. Create a one-node cluster using Minikube. 2\. Create an HTML file on the node. 3\. Create a Persistent Volume YAML file and deploy it using `kubectl`. 4\. Create a Persistent Volume Claim YAML file and deploy it using `kubectl`. 5\. Create a Pod YAML which mounts the PVC as a volume, and deploy it using `kubectl`. 6\. Bash into the container and use curl to view the HTML file from step 2—this proves that your container has access to a persistent volume. \ I hope this will be useful as you take your first steps in Kubernetes storage management.