Kubernetes NFS PersistentVolumes: Remote storage explained

Learn why Kubernetes remote storage exists and how to create a PersistentVolume backed by an NFS server. Covers static PV and PVC creation, ReadWriteMany access mode, and mounting NFS storage into a pod.

5 lessons · 16 min · Intermediate

3 minutes reading time

Written by

Civo Team
Civo Team

Marketing Team at Civo

Both emptyDir and hostPath have the same fundamental limitation: the data is tied to a specific node. If a pod is rescheduled to a different node, it no longer has access to the data it wrote previously. For production workloads, this is not acceptable.

Remote storage solves this problem. A remote volume lives outside the Kubernetes cluster entirely, on a separate server or storage system. When a pod mounts a remote volume and is later rescheduled to a different node, it reconnects to the same storage and finds the same data. The pod's location in the cluster is irrelevant.

NFS (Network File System) is one of the most common remote storage options. It is simple to set up, widely supported, and provides ReadWriteMany access mode, meaning multiple pods across different nodes can mount and write to the same volume simultaneously.

The recommended pattern for using NFS in Kubernetes is to create a PersistentVolume backed by the NFS server, then claim storage via a PVC. This abstracts the NFS server details away from the application developer.

nfs-remote-vs-local

Prerequisites

Before running this demo, ensure:

  • An NFS server is running and reachable from all cluster nodes
  • The shared path is exported with appropriate permissions on the NFS server
  • The nfs-common package is installed on all cluster nodes (Debian/Ubuntu):
sudo apt-get install -y nfs-common

On RHEL/CentOS, install nfs-utils instead:

sudo yum install -y nfs-utils

Without the NFS client packages installed on the nodes, pods will fail to mount the volume and the pod will stay in a waiting state.

Static vs dynamic NFS provisioning

This page covers static provisioning: the NFS server details are known upfront and the PersistentVolume is created manually. This is straightforward and works well when you have a single NFS server and a small number of volumes to manage.

For self-service NFS storage where developers can request volumes on demand via a StorageClass, see the dynamic provisioning guide, which covers using nfs-subdir-external-provisioner to provision NFS-backed PVs automatically.

Step 1: Create the PersistentVolume

Replace <nfs-server-ip> with the IP address of your NFS server and <shared-path> with the exported directory path.

apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: <nfs-server-ip>
path: <shared-path>
kubectl create -f pv.yaml

Step 2: Create the PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
spec:
storageClassName: manual
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
kubectl create -f pvc.yaml

Verify both are bound:

kubectl get pv,pvc

Expected output:

NAME CAPACITY ACCESS MODES STATUS STORAGECLASS
persistentvolume/pv-nfs 1Gi RWX Bound manual
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS
persistentvolumeclaim/pvc-nfs Bound pv-nfs 1Gi RWX manual

The PVC binds immediately without waiting for a pod. With static provisioning there is no WaitForFirstConsumer binding mode. The PV and PVC match on StorageClass name and access mode and bind straight away.

Step 3: Create a pod that uses the PVC

This pod mounts the NFS volume at /mnt and writes memory information to a file:

apiVersion: v1
kind: Pod
metadata:
name: pod-using-nfs
spec:
volumes:
- name: nfs-volume
persistentVolumeClaim:
claimName: pvc-nfs
containers:
- name: alpine
image: alpine
command: ["sh", "-c", "cat /proc/meminfo > /mnt/memory.txt && while true; do sleep 3600; done"]
volumeMounts:
- mountPath: /mnt
name: nfs-volume
kubectl create -f pod.yaml
kubectl get pods

Expected output:

NAME READY STATUS RESTARTS AGE
pod-using-nfs 1/1 Running 0 10s

Step 4: Verify the data

Exec into the pod:

kubectl exec -it pod-using-nfs -- sh

Navigate to the mount path and check the file:

cd /mnt
ls

Expected output:

memory.txt
cat memory.txt

The file contains memory information written by the container. The same file is simultaneously visible on the NFS server at the shared path. If the pod is deleted and recreated on a different node, it will reconnect to the same NFS share and find the file still there.

Why remote storage matters for production

emptyDir data is lost when the pod is deleted. hostPath data stays on a specific node and is inaccessible if the pod moves. NFS and other remote storage options decouple data from both pod and node lifecycle. Even if the entire Kubernetes cluster is lost, the data on the NFS server remains intact and recoverable.

This makes remote storage the right choice for any workload where data must survive pod restarts, rescheduling, or cluster failures.

Civo Team
Civo Team

Marketing Team at Civo

Civo is the Sovereign Cloud and AI platform designed to help developers and enterprises build without limits. We bridge the gap between the openness of the public cloud and the rigorous security of private environments, delivering full cloud parity across every deployment. As a team, we are dedicated to providing scalable compute, lightning-fast Kubernetes, and managed services that are ready in minutes. Through CivoStack Enterprise and our FlexCore appliance, we empower organizations to maintain total data sovereignty on their own hardware.

Our mission is to make the cloud faster, simpler, and fairer. By providing enterprise-grade NVIDIA GPUs and streamlined model management, we ensure that high-performance AI and machine learning are accessible to everyone. Built for transparency and performance, the Civo Team is here to give you total control over your infrastructure, your data, and your spend.

View author profile
Course complete

Nice work, you finished Kubernetes Volumes: Persisting and sharing data in your cluster.

Your next step is up to you - keep building on what you've learned, or put it into practice on Civo.

Next Course

Kubernetes Networking: How pods, services and nodes communicate

2 lessons · 9 min

Understand how networking works in Kubernetes. Covers the networking model, CNI plugins, pod-to-pod communication, node-to-node routing, and container networking within a pod.

Put it into practice

Spin up your first cluster on Civo

Get $250 free credit and launch a production-ready Kubernetes cluster in under 90 seconds.