Introduction to Storage Classes
The previous installment in this series outlined two volume provisioning methods, static and dynamic. The exercise on creating a PersistentVolume was based on static volume provisioning, while this segment will focus on the dynamic method using StorageClass. You’ll learn how to make a volume request of any size, without worrying about whether or not it’s available in the storage pool.
Here’s what we’ll cover:
- What is a StorageClass?
- How to create a StorageClass
- How to reference a StorageClass in a PersistentVolumeClaim (PVC)
- How do StorageClasses help to make data persistence more dynamic?
What Is a StorageClass?
A StorageClass is a Kubernetes resource that enables dynamic storage provisioning. The administrator configures the StorageClass, which can then no longer be modified. First the StorageClass is created, then the PersistentVolumeClaim and finally the Pod. When a PVC is created, Kubernetes creates a PersistentVolume and binds it to the PVC automatically, depending on the VolumeBindingMode used in the StorageClass configuration. These three Kubernetes objects are required to check the test case of a StorageClass.
How to Create and Reference a StorageClass in a PVC
Creating a StorageClass is similar to the way we created previous Kubernetes objects, except that it has its own properties and values, which will be described later. The configuration file below is an example of a StorageClass manifest file:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: my-storageclass provisioner: kubernetes.io/aws-ebs volumeBidingMode: WaitForFirstConsumer
The apiVersion, kind, and metadata are common properties that you will be familiar with from our previous exercises on Kubernetes objects. The new, additional properties are:
- Provisioner: This property is essential, and it must be specified. It is a field that determines which volume plugin should be used to provision the PVs. There are many volume plugins that are classified as either internal or external provisioners. (e.g., GCEPersistentDisk, Azuredisk, Azurefile, AWSElasticBlockStore, NFS, Flexvolume, Local, etc.). The first four use internal provisioner plugins, while the last three are external. Each of these has its config example used as part of the provisioner field’s value, depending on which volume plugin you want to use.
The table below shows the standard volume plugins and their provisioners.
You can find more volume plugins and their provisioners here Kubernetes official documentation.
volumeBindingMode: This property has two values, Immediate and WaitForFirstConsumer.
- Immediate Mode: This mode involves the automatic volume binding of PVs to PVCs with a StorageClass once a PVC is created.
- WaitForFirstConsumer Mode: This mode will delay the binding and dynamic provisioning of PVs, until a Pod that will use it is created.
The following stages will guide you through how to create and use a StorageClass.
- Create a StorageClass
- Create a PVC for storage request from StorageClass
- Create a Pod to consume the claim by referencing the PVC in the Pod
Basic knowledge of Pod, Deployment, Volume, PersistentVolume and PersistentVolumeClaim is recommended to make the most of this hands-on practice. Please refer to our previous posts on these concepts if you need to familiarize yourself with them. In addition, a running Kubernetes cluster is required for this exercise. You can simply create a single Node cluster using Kubeone. The documentation and guide can be found here.
Create a StorageClass: Here are the steps to create a StorageClass:
Step 1: Create a file with vim or any editor of your choice:
$ vim st-class.yaml
Step 2: Copy and paste the above StorageClass manifest file into the created YAML file and create the StorageClass with
kubectl create command.
$ kubectl create -f st-class.yaml storageclass.storage.k8s.io/my-storageclass created
Step 3: Check the details of the StorageClass:
$ kubectl get sc my-storageclass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE AGE my-storageclass kubernetes.io/aws-ebs Delete WaitForFirstConsumer 9s
Create a PVC: You can read more on PVC in this previous chapter in the series. A “storageClassName” property should be added to the PVC manifest file, with the StorageClass name created in stage 1 as its value, which in this case will be “my-storageclass”. When this field is omitted, the default StorageClass, which is “Standard,”, will be provisioned with the PVC. It is always suggested to reference the StorageClass name in the PVC to use the desired StorageClass. The complete configuration will look like this:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-claim spec: accessModes: - ReadWriteOnce storageClassName: my-storageclass resources: requests: storage: 2Gi
Step 1: Create the PVC with
kubectl create command:
$ kubectl create -f my-pvc.yaml persistentvolumeclaim/my-claim created
Step 2: Check the status of the PVC:
$ kubectl get pvc my-claim NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-claim Pending my-storageclass 9s
The status output shows that the PVC is pending, because WaitForFirstConsumer is used as the VolumeBindingMode value in the StorageClass configuration. It will remain in this state until a Pod that will consume the claim is created.
Now, Check the PersistentVolume status using
kubectl get command:
$ kubectl get pv No resources found
You can’t see an available PersistentVolume on the cluster, even though a PVC has been created. Delete the PVC and then the StorageClass, change the volumeBindingMode value in the StorageClass manifest file to “Immediate,” create the two objects again and check the status. You can now go to stage 3 and create a Pod.
Create a Pod to consume the claim: The previous configuration will be used. The PVC name must be the same as the persistentClaimVolume.claimName field’s value in the Pod. The configuration will look like this:
$ vim st-pod.yaml
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: stclass-test image: nginx volumeMounts: - mountPath: "/app/data" name: my-volume volumes: - name: my-volume persistentVolumeClaim: claimName: my-claim
Step 1: Create the Pod with
kubectl create command:
$ kubectl create -f st-pod.yaml pod/my-pod created
Step 2: Check the Pod status:
$ kubectl get pods my-pod NAME READY STATUS RESTARTS AGE my-pod 1/1 Running 0 3m
Check the status of the PVC again:
$ kubectl get pvc my-claim NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-claim Bound pvc-6e5dae64 2Gi RWO my-storageclass 10m
As shown above, the status of the PVC has changed from a pending to a bound state. This simply means that all three objects created are now bound or reference one another.
The next step is to check the PersistentVolume status again using the
kubectl get command:
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS AGE pvc-6e5dae64 2Gi RWO Delete Bound default/my-claim my-storageclass 99s
If everything works correctly, you should see the same output as above. You can now see that a PersistentVolume was automatically created when we created the Pod. This is dynamic volume provisioning using StorageClass.
The persistent functionality can be tested using ssh in the Pod; create and save a file inside the Pod, then delete the Pod. Re-create the Pod again and check for the file that was created before deleting the Pod. You can do this by following these steps:
Step 1: Exec into the Pod:
$ kubectl exec -it my-pod -- bin/bash root@my-pod:/#
Step 2: Change to the mount directory—The same directory for volumeMount in the Pod manifest file.
root@my-pod:/# cd app/data root@my-pod:/app/data#
Step 3: Create and store some data in a text file and check the file to be sure the data is written in the file, and exit the Pod:
root@my-pod:/app/data# echo My StorageClass Message > stclass.txt root@my-pod:/app/data# cat stclass.text My StorageClass Message
Step 4: Now delete the Pod:
$ kubectl delete pod my-pod pod "my-pod" deleted
$ kubectl get pods No resources found
$ kubectl create -f st-pod.yaml pod/my-pod created
Check the Pod status to confirm if it is running:
$ kubectl get pods NAME READY STATUS RESTARTS AGE my-pod 1/1 Running 0 89s
Step 5: Exec into the Pod again and check that the file was created before the Pod was deleted:
$ kubectl exec -it my-pod -- bin/bash root@my-pod:/# cd /app/data root@my-pod:/app/data# ls stclass.text root@my-pod:/app/data# cat stclass.text My StorageClass Message
The data that was created remained beyond the Pod’s lifecycle
Delete the Pod, PVC, and the StorageClass using the
kubectl delete command.
Summary: StorageClass is a Kubernetes object that preserves your application data by storing it in the cloud. It is based on which volume plugin is used to provision the StorageClass. (e.g., in the above case, the AWS cloud). Manual provisioning of PersistentVolume in advance is not required, as it is in the static provisioning method. Instead, the StorageClass object must be created before the PersistentVolumeClaim.
Next in our series, we’ll look at the best practice for taking care of stateful applications by introducing another Kubernetes object, a StatefulSet. Applications in Kubernetes can be either stateful or stateless. We have worked on various stateless applications in previous parts of this series, so the next will focus on creating applications using a StatefulSet.
We’d love to hear from you! Please do not hesitate to contact us with any thoughts or questions, or any clarifications you might want about Storage Classes.