8th Week :- Build Rock-Solid Storage in Kubernetes: Static & Dynamic PVCs with NFS + MongoDB

Lav kushwahaLav kushwaha
5 min read

πŸ“¦ What are Volumes in Kubernetes?

In Kubernetes, volumes are used to persist and share data across containers and pod restarts. By default, data inside a pod disappears when the container restarts or the pod is deleted. Volumes solve this issue by providing persistent storage outside the lifecycle of containers.


πŸ’‘ Why Use Volumes?

  • βœ… Retain data after pod restarts.

  • βœ… Share data between multiple containers in a pod.

  • βœ… Use external storage (NFS, cloud storage, etc.)

  • βœ… Store databases, logs, uploads, etc.

  • βœ… Separate compute (pods) from storage.


πŸ“‚ Types of Volumes in Kubernetes

1. Ephemeral Volumes

  • Lives and dies with the pod.

  • Example: emptyDir, configMap, secret, downwardAPI

  • Use case: Temporary cache, scratch space

volumes:
  - name: temp-storage
    emptyDir: {}

2. Persistent Volumes (PV)

  • An actual storage resource (disk, NFS, cloud block storage).

  • Lives beyond pod lifecycle.


3. PersistentVolumeClaim (PVC)

  • A user’s request for a PV.

  • Binds to an available PV that satisfies the claim.


🧱 Provisioning Methods: Static vs. Dynamic

TypeWho creates the PV?Use Case
Static ProvisioningAdmin manually creates PVsOn-prem or controlled environments
Dynamic ProvisioningK8s auto-creates PVs via StorageClassCloud-native apps, automation

πŸ”¨ Static Provisioning with NFS

Prerequisites:

  • NFS server running

  • Shared NFS directory (e.g., /srv/nfs/kubedata)

  • Exported in /etc/exports

➀ NFS Server (Example)

sudo apt install nfs-kernel-server
sudo mkdir -p /srv/nfs/kubedata
sudo chmod -R 777 /srv/nfs/kubedata
echo "/srv/nfs/kubedata *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
sudo exportfs -rav

🧾 Step 1: Create Static PersistentVolume

# nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /srv/nfs/kubedata
    server: <NFS-SERVER-IP>

🧾 Step 2: Create PVC to Use This PV

# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

🧾 Step 3: Create Pod Using This PVC

# pod-using-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nfs-app
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nfs-storage
  volumes:
    - name: nfs-storage
      persistentVolumeClaim:
        claimName: nfs-pvc

🧰 Static Provisioning Using NFS on a Cloud VM

We’ll now create a static NFS volume by setting up a remote NFS server on a cloud VM, such as AWS EC2, Google Compute Engine, or Azure VM.

☁️ Step 1: Launch a VM (e.g., AWS EC2)

  • OS: Ubuntu 20.04

  • Open ports:

    • 22 (SSH)

    • 2049 (NFS) β€” allow access from your Kubernetes nodes


πŸ”‘ Step 2: SSH into the VM

ssh -i <your-key.pem> ubuntu@<EC2_PUBLIC_IP>

πŸ“‚ Step 3: Install & Configure NFS Server

sudo apt update
sudo apt install nfs-kernel-server -y
sudo mkdir -p /srv/nfs/kubedata
sudo chmod -R 777 /srv/nfs/kubedata

Then edit /etc/exports:

sudo nano /etc/exports

Add:

/srv/nfs/kubedata *(rw,sync,no_subtree_check,no_root_squash)

Apply changes:

sudo exportfs -rav
sudo systemctl restart nfs-kernel-server

πŸ” Note the private IP of this VM (use hostname -I). We'll use it next.


🧾 Step 4: Create PersistentVolume (PV)

# cloud-nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: cloud-nfs-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /srv/nfs/kubedata
    server: <VM-PRIVATE-IP>  # replace with actual IP

🧾 Step 5: Create PVC and Pod

# cloud-nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cloud-nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
# cloud-nfs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nfs-app
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: cloud-nfs-storage
  volumes:
    - name: cloud-nfs-storage
      persistentVolumeClaim:
        claimName: cloud-nfs-pvc

πŸ” Dynamic Provisioning using StorageClass (Automatic PV)

🧾 Step 1: Define StorageClass

# storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-storage
provisioner: kubernetes.io/aws-ebs  # use nfs or other provisioners based on environment
parameters:
  type: gp2
reclaimPolicy: Retain
volumeBindingMode: Immediate

Note: For local testing with NFS, use nfs-subdir-external-provisioner


🧾 Step 2: Create PVC with StorageClass

# mongodb-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: fast-storage

🧾 Step 3: Create MongoDB Deployment

# mongodb-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
        - name: mongodb
          image: mongo
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-storage
              mountPath: /data/db
      volumes:
        - name: mongo-storage
          persistentVolumeClaim:
            claimName: mongodb-pvc

βœ… How to Check Volume is Working or Not

πŸ” 1. Check PVC Binding

kubectl get pvc
kubectl describe pvc <pvc-name>

πŸ” 2. Check PV Status

kubectl get pv
kubectl describe pv <pv-name>

πŸ” 3. Verify Pod Logs / Shell

kubectl exec -it <pod-name> -- /bin/bash
# Inside pod
cd /data/db    # or your mounted volume path
touch test.txt # Check if it persists

πŸ” 4. Delete and Recreate Pod

kubectl delete pod <pod-name>
kubectl apply -f pod.yaml
# Check if /data/db/test.txt is still there

🧠 Pro Tips

  • Use ReadWriteMany for shared storage (e.g., NFS).

  • Set persistentVolumeReclaimPolicy: Retain to keep data even after PVC deletion.

  • Label your PVs to allow PVCs to match specific volumes.

  • For cloud providers, choose the right provisioner (aws-ebs, gce-pd, csi-driver, etc.)

  • Monitor Events: section in kubectl describe to troubleshoot storage binding.


πŸš€ Conclusion

Kubernetes volumes are essential to run real-world applications with stateful data. Whether you're working with NFS static PVs or dynamic StorageClasses, understanding the role of PVCs and PVs is crucial. With these examples and verification tricks, you’re ready to deploy databases and other apps with robust storage backing.

0
Subscribe to my newsletter

Read articles from Lav kushwaha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lav kushwaha
Lav kushwaha