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.
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 -yfor CentOS or
apt install nfs-kernel-server -yfor 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.
Linux Ops Smart Journey
The operations journey never stops—pursuing excellence endlessly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.