Skip to content

Changing the Default Storage Class to NFS

By default, K3s installs the local-path storage class as default. This makes sense for simple or single-node setups but is often insufficient for multi-node clusters or when you need persistent volumes backed by network storage. Below, we’ll disable the local-path default and install the NFS subdir external provisioner so that new PersistentVolumeClaims (PVCs) are automatically created on an NFS server.

1. Patch the Existing Local-Path Storage Class

We want to ensure that local-path no longer claims the role of “default” storage class. Once patched, you can still use local-path volumes explicitly, but new PVCs without a specified storage class will be allocated from the NFS-based default.

Run the following command to patch the local-path storage class:

kubectl patch storageclass local-path \
  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
  • This removes the “default class” annotation from local-path.
  • Verify the patch by running:
kubectl get storageclass

You should see something like:

NAME                 PROVISIONER               RECLAIMPOLICY   VOLUMEBINDINGMODE   ...
local-path           rancher.io/local-path     Delete          WaitForFirstConsumer ...

Notice there is no (default) next to local-path anymore.


2. Install the NFS Subdir External Provisioner

The NFS subdir external provisioner is a lightweight way to dynamically create subdirectories on an existing NFS share for each PVC. It can be designated as your new default storage class.

  1. Identify Your NFS Server and Path

    • Suppose you can mount NFS like this:
    sudo mount 44.223.98.19:/nfs1 /nfs
    

    Then: - nfs_server is 44.223.98.19 - nfs_path is /nfs1

  2. Add the Helm Repository and Create a New Namespace

    nfs_server="44.223.98.19"
    nfs_path="/nfs1"
    
    kubectl create namespace nfs-storage
    
    helm repo add nfs-subdir-external-provisioner "https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/"
    helm repo update
    
  3. Install the NFS Subdir External Provisioner
    Run the following Helm install command, ensuring you enable default storage class:

    helm install nfs-subdir-external-provisioner \
      nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
      --namespace nfs-storage \
      --set nfs.server=$nfs_server \
      --set nfs.path=$nfs_path \
      --set storageClass.defaultClass=true
    
    • --set nfs.server: The IP or hostname of your NFS server.
    • --set nfs.path: The base directory on the NFS server where subdirectories will be created.
    • --set storageClass.defaultClass=true: Tells the provisioner to mark its storage class as default.
  4. Confirm the New Default Class

    kubectl get storageclass
    

    You should now see something like:

    NAME                   PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    local-path             rancher.io/local-path                           Delete          WaitForFirstConsumer   false                  42m
    nfs-client (default)   cluster.local/nfs-subdir-external-provisioner   Delete          Immediate              true                   7s
    

    With nfs-subdir-external-provisioner flagged as (default).


3. Verify Dynamic Provisioning on NFS

  1. Create a Test PVC without specifying a storage class:

    Create a file called pvc-test.yaml and paste the following content:

    # pvc-test.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: test-pvc
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    
    kubectl apply -f pvc-test.yaml
    
  2. Check the PVC and Bound PV:

    kubectl get pvc test-pvc
    

    The status should transition to Bound. A PersistentVolume will be automatically created, and a matching directory appears in your NFS share (/nfs1/).

  3. Inspect the Storage Class:

    kubectl describe pvc test-pvc
    

    The Events: section should show the storage has been successfully provisioned. Example:

    Events:
    Type    Reason                 Age                From                                                                                                                                 Message
    ----    ------                 ----               ----                                                                                                                                 -------
    Normal  ExternalProvisioning   27s (x2 over 27s)  persistentvolume-controller                                                                                                          Waiting for a volume to be created either by the external provisioner 'cluster.local/nfs-subdir-external-provisioner' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.
    Normal  Provisioning           27s                cluster.local/nfs-subdir-external-provisioner_nfs-subdir-external-provisioner-587d45f4c4-m54p4_583f726b-870b-4a18-b56e-706887870854  External provisioner is provisioning volume for claim "default/test-pvc"
    Normal  ProvisioningSucceeded  27s                cluster.local/nfs-subdir-external-provisioner_nfs-subdir-external-provisioner-587d45f4c4-m54p4_583f726b-870b-4a18-b56e-706887870854  Successfully provisioned volume pvc-c6648e6f-0861-4d51-acac-4a16262fc17d
    

4. Remove the Test NFS PVC

To clean up and remove the test PVC and associated PersistentVolume (PV) after verifying the NFS storage class, follow these steps:

  1. Delete the test-pvc PersistentVolumeClaim (PVC) using the kubectl delete command:

    kubectl delete -f pvc-test.yaml
    

    This will automatically delete the associated PersistentVolume (PV) created by the NFS storage class.

  2. Verify PVC and PV Deletion

    Check that the PVC and PV have been successfully deleted:

    kubectl get pvc -A
    kubectl get pv -A
    

    Both the test-pvc PVC and its associated PV should no longer appear in the output.

  3. Delete the test-pvc.yaml file

    If you no longer need the pvc-test.yaml file, you can remove it:

    rm pvc-test.yaml
    

4. Conclusion

By patching the existing local-path storage class to not be the default and installing the NFS subdir external provisioner with --set storageClass.defaultClass=true, you’ve now made NFS the default storage class in your K3s cluster. Any new PVCs without an explicit storageClassName will automatically be provisioned on your remote NFS server, allowing multiple nodes in your cluster to share data seamlessly.

If you still need local-path volumes for specialized workloads, you can specify storageClassName: local-path in a given PVC. Otherwise, your cluster now defaults to NFS.