K8s: NFS Dynamic Provisioner with ReadWriteMany (RWX) Volumes

K8s: NFS Dynamic Provisioner with ReadWriteMany (RWX) Volumes

Kubernetes supports many types of volumes. A Pod can use any number of volume types simultaneously. Ephemeral volume types have a lifetime of a pod, but persistent volumes exist beyond the lifetime of a pod. When a pod ceases to exist, Kubernetes destroys ephemeral volumes; however, Kubernetes does not destroy persistent volumes. 

At its core, a volume is a directory, possibly with some data in it, which is accessible to the containers in a pod. How that directory comes to be, the medium that backs it, and the contents of it are determined by the particular volume type used.

Types of Persistent Volumes

PersistentVolume types are implemented as plugins. Kubernetes currently supports the following plugins:

  • csi – Container Storage Interface (CSI)
  • fc – Fibre Channel (FC) storage
  • hostPath – HostPath volume (for single node testing only; WILL NOT WORK in a multi-node cluster; consider using local volume instead)
  • iscsi – iSCSI (SCSI over IP) storage
  • local – local storage devices mounted on nodes.
  • nfs – Network File System (NFS) storage

Access Modes 

A PersistentVolume can be mounted on a host in any way supported by the resource provider. As shown in the table below, providers will have different capabilities and each PV’s access modes are set to the specific modes supported by that particular volume. For example, NFS can support multiple read/write clients, but a specific NFS PV might be exported on the server as read-only. Each PV gets its own set of access modes describing that specific PV’s capabilities.

The access modes are:

  • ReadWriteOnce

the volume can be mounted as read-write by a single node. ReadWriteOnce access mode still can allow multiple pods to access the volume when the pods are running on the same node.

  • ReadOnlyMany

the volume can be mounted as read-only by many nodes.

  • ReadWriteMany

the volume can be mounted as read-write by many nodes.

  • ReadWriteOncePod

FEATURE STATE: Kubernetes v1.27 [beta]

the volume can be mounted as read-write by a single Pod. Use ReadWriteOncePod access mode if you want to ensure that only one pod across the whole cluster can read that PVC or write to it. This is only supported for CSI volumes and Kubernetes version 1.22+.

In the CLI, the access modes are abbreviated to:

  • RWO – ReadWriteOnce
  • ROX – ReadOnlyMany
  • RWX – ReadWriteMany
  • RWOP – ReadWriteOncePod
Volume PluginReadWriteOnceReadOnlyManyReadWriteManyReadWriteOncePod
AzureFile
CephFS
CSIdepends on the driverdepends on the driverdepends on the driverdepends on the driver
FC
FlexVolumedepends on the driver
GCEPersistentDisk
Glusterfs
HostPath
iSCSI
NFS
RBD
VsphereVolume– (works when Pods are collocated)
PortworxVolume

Storge Class

A PV can have a class, which is specified by setting the storageClassName attribute to the name of a StorageClass. A PV of a particular class can only be bound to PVCs requesting that class. A PV with no storageClassName has no class and can only be bound to PVCs that request no particular class.

Kubernetes StorageClass provides a way for administrators to describe the “classes” of storage they offer. Different classes might map to quality-of-service levels, to backup policies, or to arbitrary policies determined by the cluster administrators.

Each StorageClass has a provisioner that determines what volume plugin is used for provisioning PVs.

Kubernetes doesn’t include an internal NFS provisioner. You need to use an external provisioner to create a StorageClass for NFS. 

NFS subdir external provisioner

NFS subdir external provisioner is an automatic provisioner that uses your existing and already configured NFS server to support dynamic provisioning of Kubernetes Persistent Volumes via Persistent Volume Claims. Persistent volumes are provisioned as ${namespace}-${pvcName}-${pvName}.

An NFS storage provisioner is sufficient for development environments and workloads with low I/O performance requirements.

Deployment With Helm:

This chart installs a custom storage class into a Kubernetes cluster using the Helm package manager. It also installs an NFS client provisioner into the cluster which dynamically creates persistent volumes from a single NFS share.

$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/

$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner –create-namespace -n nfs-provisioner –set nfs.server=x.x.x.x  –set nfs.path=/exports  –set storageClass.name=nfs-client  –set storageClass.onDelete=delete

Verification

 $ kubectl get all -n nfs-provisioner

$ kubectl get sc

$ kubectl describe sc nfs-client

Test NFS subdir external provisioner.

$ Kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/test-claim.yaml

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

$ Kubectl get pvc

$ kubectl exec nfs-server-6b4cbd849c-8p6c8 — ls /exports/default-test-claim-pvc-324a066b-0c40-436e-a9c8-0cbc47a2dda3

NFS provisioner limitations/pitfalls:

  • The provisioned storage is not guaranteed. You may allocate more than the NFS share’s total size. The share may also not have enough storage space left to actually accommodate the request.
  • The provisioned storage limit is not enforced. The application can expand to use all the available storage regardless of the provisioned size.
  • Storage resize/expansion operations are not presently supported in any form.

Configuration

The following tables list the configurable parameters of the Helm chart and their default values.

ParameterDescriptionDefault
replicaCountNumber of provisioner instances to deployed1
strategyTypeSpecifies the strategy used to replace old Pods by new onesRecreate
image.repositoryProvisioner imageregistry.k8s.io/sig-storage/nfs-subdir-external-provisioner
image.tagVersion of provisioner imagev4.0.2
image.pullPolicyImage pull policyIfNotPresent
imagePullSecretsImage pull secrets[]
storageClass.nameName of the storageClassnfs-client
storageClass.defaultClassSet as the default StorageClassfalse
storageClass.allowVolumeExpansionAllow expanding the volumetrue
storageClass.reclaimPolicyMethod used to reclaim an obsoleted volumeDelete
storageClass.provisionerNameName of the provisionerNamenull
storageClass.archiveOnDeleteArchive PVC when deletingtrue
storageClass.onDeleteStrategy on PVC deletion. Overrides archiveOnDelete when set to lowercase values ‘delete’ or ‘retain’null
storageClass.pathPatternSpecifies a template for the directory namenull
storageClass.accessModesSet access mode for PVReadWriteOnce
storageClass.volumeBindingModeSet volume binding mode for Storage ClassImmediate
storageClass.annotationsSet additional annotations for the StorageClass{}
leaderElection.enabledEnables or disables leader electiontrue
nfs.serverHostname of the NFS server (required)null (ip or hostname)
nfs.pathBasepath of the mount point to be used/nfs-storage
nfs.mountOptionsMount options (e.g. ‘nfsvers=3’)null
nfs.volumeNameVolume name used inside the podsnfs-subdir-external-provisioner-root
nfs.reclaimPolicyReclaim policy for the main nfs volume used for subdir provisioningRetain
resourcesResources required (e.g. CPU, memory){}
rbac.createUse Role-based Access Controltrue
podSecurityPolicy.enabledCreate & use Pod Security Policy resourcesfalse
podAnnotationsAdditional annotations for the Pods{}
priorityClassNameSet pod priorityClassNamenull
serviceAccount.createShould we create a ServiceAccounttrue
serviceAccount.nameName of the ServiceAccount to usenull
serviceAccount.annotationsAdditional annotations for the ServiceAccount{}
nodeSelectorNode labels for pod assignment{}
affinityAffinity settings{}
tolerationsList of node taints to tolerate[]
labelsAdditional labels for any resource created{}
podDisruptionBudget.enabledCreate and use Pod Disruption Budgetfalse
podDisruptionBudget.maxUnavailableSet maximum unavailable pods in the Pod Disruption Budget1

/

References:

Helm

Kubernetes Storage

NFS Subdirectory External Provisioner

Leave a comment