Cloud Native 14 min read

How to Deploy NFS Subdir External Provisioner on Kubernetes with HA

This guide walks through deploying the NFS‑subdir‑external‑provisioner on Kubernetes, covering migration to the new repository, configuring storage classes with subdirectory support, applying RBAC resources, creating PVCs, enabling high‑availability with leader election, and troubleshooting common mount errors.

Ops Development Stories
Ops Development Stories
Ops Development Stories
How to Deploy NFS Subdir External Provisioner on Kubernetes with HA

Background

NFS is a common volume storage option in Kubernetes, but the original nfs-client-provisioner repository has been archived. The maintained fork at

https://github.com/lorenzofaresin/nfs-subdir-external-provisioner

adds a pathPattern parameter that allows per‑PVC subdirectory configuration.

Deploying the Provisioner

Create the required YAML files (StorageClass, Deployment, RBAC) and adjust the NFS server IP and path to match your environment.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: kube-system
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
      - name: nfs-client-provisioner
        image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
        env:
        - name: PROVISIONER_NAME
          value: k8s-sigs.io/nfs-subdir-external-provisioner
        - name: NFS_SERVER
          value: 172.16.33.4
        - name: NFS_PATH
          value: /
        volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentvolumes
      volumes:
      - name: nfs-client-root
        nfs:
          server: 172.16.33.4
          path: /
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get","list","watch"]
- apiGroups: [""]
  resources: ["persistentvolumes"]
  verbs: ["get","list","watch","create","delete"]
- apiGroups: [""]
  resources: ["persistentvolumeclaims"]
  verbs: ["get","list","watch","update"]
- apiGroups: ["storage.k8s.io"]
  resources: ["storageclasses"]
  verbs: ["get","list","watch"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["create","update","patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
  name: nfs-client-provisioner
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: kube-system
rules:
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get","list","watch","create","update","patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: nfs-client-provisioner
  namespace: kube-system
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
Note: If the image cannot be pulled, pull it from an external machine and import it. RBAC usually does not need changes; adjust class.yaml when configuring subdirectories.

Apply all resources:

kubectl apply -f class.yaml -f deployment.yaml -f rbac.yaml

Creating a PVC

Example PVC that uses the storage class:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-pvc-2
  namespace: nacos
spec:
  storageClassName: "managed-nfs-storage"
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

After creating a StatefulSet that mounts this PVC, Kubernetes automatically creates a corresponding PV and binds it.

Configuring Subdirectories

Update class.yaml to add the pathPattern parameter, then recreate the StorageClass.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"
  pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}"

Create a PVC with the annotation that defines the subdirectory:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-pvc-2
  namespace: nacos
  annotations:
    nfs.io/storage-path: "test-path-two"
spec:
  storageClassName: "managed-nfs-storage"
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 100Mi

Apply the resources and verify that the NFS server now contains a directory structure like /data/nfs/nacos/test-path-two, confirming the subdirectory logic works.

Provisioner High Availability

For production, run three replicas and enable leader election:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: kube-system
spec:
  replicas: 3
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
      - name: nfs-client-provisioner
        image: www.ayunw.cn/nfs-subdir-external-provisioner:v4.0.2-31-gcb203b4
        env:
        - name: PROVISIONER_NAME
          value: k8s-sigs.io/nfs-subdir-external-provisioner
        - name: ENABLE_LEADER_ELECTION
          value: "True"
        - name: NFS_SERVER
          value: 172.16.33.4
        - name: NFS_PATH
          value: /
        volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentvolumes
      volumes:
      - name: nfs-client-root
        nfs:
          server: 172.16.33.4
          path: /

Re‑apply the updated class and deployment, then check that three pods are running and one has acquired the leader lease, confirming HA is active.

Troubleshooting

If pods fail to mount the NFS volume, the typical cause is a missing NFS client on the node. Install it with:

yum install -y nfs-utils   # or apt-get install nfs-common

After installing the client, the mount succeeds.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Cloud Nativehigh availabilityKubernetesstorageYAMLNFSProvisioner
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

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.