Cloud Native 9 min read

How to Integrate NFS Storage with Kubernetes: Static & Dynamic Provisioning Guide

This tutorial walks through the prerequisites, static and dynamic provisioning steps, and verification commands for integrating NFS storage into a Kubernetes cluster, providing complete YAML manifests and shell commands to create PVs, PVCs, Deployments, and StorageClasses.

Linux Ops Smart Journey
Linux Ops Smart Journey
Linux Ops Smart Journey
How to Integrate NFS Storage with Kubernetes: Static & Dynamic Provisioning Guide

This article follows a previous post on local‑mode storage and now explains how to integrate NFS with Kubernetes, covering both static and dynamic provisioning.

Prerequisites

Deploy an NFS service.

Install NFS client utilities on all Kubernetes nodes (e.g.,

yum install nfs-utils -y

for CentOS or

apt install nfs-kernel-server -y

for Ubuntu).

Verify network connectivity from each node to the NFS server:

<code>$ showmount -e 172.139.20.170
Export list for 172.139.20.170:
/data/nfs 172.139.20.0/24</code>

2.1 Static Provisioning

Create a NFS‑type PersistentVolume (PV):

<code>cat <<EOF | kubectl apply -f-
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-nfs-static-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /data/nfs
    server: 172.139.20.170
EOF</code>

Create a PersistentVolumeClaim (PVC):

<code>cat <<EOF | kubectl apply -f-
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-nfs-static-pvc
spec:
  accessModes:
    - ReadWriteMany
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
EOF</code>

Deploy a pod that uses the PVC:

<code>$ cat <<EOF | kubectl apply -f-
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tools
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tools
  template:
    metadata:
      labels:
        app: tools
    spec:
      containers:
      - name: tools
        image: registry.cn-guangzhou.aliyuncs.com/jiaxzeng6918/tools:v1.1
        volumeMounts:
        - name: data
          mountPath: /data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: test-nfs-static-pvc
EOF</code>

Check the mount point inside the pod:

<code>$ kubectl exec -it tools-7b8969fd94-cdhj2 -- df -h /data
Filesystem               Size  Used Avail Use% Mounted on
172.139.20.170:/data/nfs  62G   11G   52G  17% /data</code>

Tip: In my tests, static NFS provisioning does not enforce PVC size limits.

2.2 Dynamic Provisioning

Download the NFS dynamic provisioner files:

<code>$ curl -LO https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/archive/refs/heads/master.zip
$ sudo unzip -d /etc/kubernetes/addons master.zip
$ sudo mv /etc/kubernetes/addons/nfs-subdir-external-provisioner-master /etc/kubernetes/addons/nfs-dynamic</code>

Create the required RBAC resources:

<code>$ sudo sed -ri 's@(namespace):.*@\1: kube-system@g' /etc/kubernetes/addons/nfs-dynamic/deploy/rbac.yaml
$ kubectl apply -f /etc/kubernetes/addons/nfs-dynamic/deploy/rbac.yaml</code>

Modify and apply the deployment manifest (adjust NFS server, path, provisioner name, image, and namespace as needed) and start the provisioner:

<code># Example modifications (variables omitted for brevity)
$ sudo sed -ri "s@[email protected]@g" /etc/kubernetes/addons/nfs-dynamic/deploy/deployment.yaml
$ sudo sed -ri "s@$NFS_PATH@/data/nfs@g" /etc/kubernetes/addons/nfs-dynamic/deploy/deployment.yaml
$ sudo sed -ri "[email protected]/nfs-subdir-external-provisioner@k8s/nfs-provisioner@g" /etc/kubernetes/addons/nfs-dynamic/deploy/deployment.yaml
$ sudo sed -ri "s@(image):.*@\1: 172.139.20.170:5000/library/nfs-subdir-external-provisioner:v4.0.2@g" /etc/kubernetes/addons/nfs-dynamic/deploy/deployment.yaml
$ sudo sed -ri "s@(namespace):.*@\1: kube-system@g" /etc/kubernetes/addons/nfs-dynamic/deploy/deployment.yaml
$ kubectl apply -f /etc/kubernetes/addons/nfs-dynamic/deploy/deployment.yaml
$ kubectl -n kube-system get pod -l app=nfs-client-provisioner</code>

Create a StorageClass for dynamic provisioning:

<code># Adjust the StorageClass name and provisioner
$ sudo sed -ri 's@(name):.*@\1: nfs-storage@g' /etc/kubernetes/addons/nfs-dynamic/deploy/class.yaml
$ sudo sed -ri "s@(provisioner):.*@\1: k8s/nfs-provisioner@g" /etc/kubernetes/addons/nfs-dynamic/deploy/class.yaml
$ echo 'reclaimPolicy: Retain' | sudo tee -a /etc/kubernetes/addons/nfs-dynamic/deploy/class.yaml
$ kubectl apply -f /etc/kubernetes/addons/nfs-dynamic/deploy/class.yaml</code>

Create a PVC that uses the new StorageClass:

<code>cat <<EOF | kubectl apply -f-
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-nfs-dynamic-pvc
spec:
  storageClassName: nfs-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1024Mi
EOF</code>

Deploy a pod that consumes the dynamic PVC:

<code>cat <<EOF | kubectl apply -f-
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tools
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tools
  template:
    metadata:
      labels:
        app: tools
    spec:
      containers:
      - name: tools
        image: registry.cn-guangzhou.aliyuncs.com/jiaxzeng6918/tools:v1.1
        volumeMounts:
        - name: data
          mountPath: /data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: test-nfs-dynamic-pvc
EOF</code>

Verify the mount point:

<code>$ kubectl exec -it tools-56bcdfb6c9-bzpm9 -- df -h /data
Filesystem                                                                 Size  Used Avail Use% Mounted on
172.139.20.170:/data/nfs/default-test-nfs-dynamic-pvc-pvc-15843d02-896b-4e3b-8f9d-c2b1310e463e   62G   11G   52G  17% /data</code>

Tip: In my tests, dynamic NFS provisioning also does not enforce PVC size limits.

Conclusion

Integrating external storage with Kubernetes extends the storage capabilities of containerized applications and provides more flexible, efficient data management. As cloud‑native technologies evolve, we anticipate further seamless storage solutions that will drive innovation and empower businesses.

cloud nativeKubernetesNFSPersistent VolumeDynamic ProvisioningStatic Provisioning
Linux Ops Smart Journey
Written by

Linux Ops Smart Journey

The operations journey never stops—pursuing excellence endlessly.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.