Kubermatic branding element

Keeping the State of Apps 5: Introduction to Storage Classes

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 Kubernetes 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.

plugins and their provisioners

You can find more volume plugins and their provisioners in the 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.

Stages:

  1. Create a StorageClass
  2. Create a PVC for storage request from StorageClass
  3. Create a Pod to consume the claim by referencing the PVC in the Pod

Hands-on Practice

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.

Stage 1:

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

Stage 2:

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.

Stage 3:

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

Recreate it:

$ 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

Clean-Up:

To clean up your Kubernetes environment after this exercise, you can delete the Pod, PVC, and StorageClass using the kubectl delete command. This ensures that no residual resources are left running in your cluster, especially if you’re managing limited resources.

By using the command kubectl delete storageclass, you can remove the StorageClass resource from your Kubernetes cluster when it’s no longer needed, making sure you’re not using up resources you don’t need.

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 Kubernetes Storage Classes.

Learn More

Seyi Ewegbemi

Seyi Ewegbemi

Student Worker