12- NFS Server Installation & Kubernetes Storage Class

A StorageClass in Kubernetes is a way to define different types of storage that can be dynamically provisioned for PersistentVolumeClaims (PVCs). Each StorageClass can represent different storage backends (e.g., local SSDs, NFS, Ceph, GlusterFS, AWS EBS, Azure Disk, GCP Persistent Disk, MinIO). Without a StorageClass, You would have to manually create PersistentVolumes (PVs) before apps can claim them. Using storage class saves time, reduces manual errors, and makes storage management flexible and scalable.

 

Before we go any further in Kubernetes subjects, It would be good to create a NFS StorageClass that serves persitent disk space for our pods. NFS can provide both ReadWriteOnce and ReadWriteMany capabilities and its widely used. I will install NFS server role on a Ubuntu VM. NFS mount point will be /mnt/nfs.

 

Ubuntu NFS Server IP Address: 192.168.204.29

NFS Mount Point: /mnt/nfs

K8s Worker Nodes' Subnet: 192.168.204.0/24

apt update
apt install nfs-kernel-server -y
mkdir -p /mnt/nfs
chown nobody:nogroup /mnt/nfs
chmod 777 /mnt/nfs
nano /etc/exports

#Add the below wntry in /etc/exports
/mnt/nfs 192.168.204.0/24(rw,sync,no_subtree_check,no_root_squash)

exportfs -rav
systemctl restart nfs-kernel-server

 

On Kubernetes Worker nodes, intsall nfs-utils

dnf install -y nfs-utils

#The command below will test the connection to nfs server. If there is no error, NFS server is successfully configured.
mount -t nfs -o nfsvers=3 192.168.204.29:/mnt/nfs /mnt

 

StorageClass:

On our Kubernetes Management Computer (in my case, my laptop), run the following. It downloads and applies the RBAC (permissions) manifest for the NFS Subdir External Provisioner. In other words, it sets up the service account and permissions the provisioner needs to create/delete PersistentVolumes on your cluster.

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml

 

Create a file named "nfs-client-deploy.yaml" with the following content

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs-client
            - name: NFS_SERVER
              value: 192.168.204.29
            - name: NFS_PATH
              value: /mnt/nfs
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.204.29
            path: /mnt/nfs

 

Then apply it

kubectl apply -f nfs-client-deploy.yaml

This yaml file deploys the NFS Subdir External Provisioner so your cluster can dynamically provision PersistentVolumes on an NFS share

 

 

Create a yaml file named "nfs-client-storageclass.yaml" with the following content. This yaml file defines a StorageClass for dynamic NFS volumes provided by your NFS Subdir External Provisioner.

Dynamically created PVs from this class will have ReclaimPolicy=Delete. When the claim is removed, the PV object is deleted and the provisioner cleans up storage

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: nfs-client
parameters:
  archiveOnDelete: "false"
reclaimPolicy: Delete
volumeBindingMode: Immediate

 

kubectl apply -f nfs-client-storageclass.yaml

 

 

We just created our first StorageClass above. According to your disk types and speed you can have multiple StorageClasses and assign them to your Pods accordingly. If you have multiple StorageClass, you might want to choose one of them as the default StorageClass. I just added annotations to "nfs-client-storageclass.yaml" and applied it again.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: nfs-client
parameters:
  archiveOnDelete: "false"
reclaimPolicy: Delete
volumeBindingMode: Immediate

 

kubectl apply -f nfs-client-storageclass.yaml

 

Let us see details for this StorageClass

 

Now we can create a PVC and use the StorageClass we created above. I will create 2 PVCs to demostrate different modes (RWO & RWX)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim1
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: nfs-client
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim2
spec:
  accessModes:
  - ReadWriteMany
  storageClassName: nfs-client
  resources:
    requests:
      storage: 500Mi

 

If we delete PVCs, PVs will be deleted automatically.