# NAS storage — Synology 425+ # Share: 192.168.40.96:/volume1/samantha-private (the only NAS share k3s uses) # # Uses kubernetes-sigs/nfs-subdir-external-provisioner: # any PVC that asks for storageClassName: nas-nfs automatically gets a subdir # carved out of the share. Subdir name = ${namespace}-${pvc}-${pv} by default, # or see pathPattern annotation on a PVC to override. # # Prerequisites (one-time): # - apt install nfs-common on every k3s node (handled via # k3s/scripts/install-nfs-common.sh + on-all-nodes.sh) # # Deploy (cluster-scoped): # kubectl apply -f nas-pv.yaml # # Usage in a service manifest (note: storageClassName: nas-nfs): # apiVersion: v1 # kind: PersistentVolumeClaim # metadata: # name: foo-data # annotations: # nfs.io/storage-path: "foo" # subdir literal name (optional) # spec: # storageClassName: nas-nfs # accessModes: [ReadWriteMany] # resources: # requests: # storage: 10Gi --- apiVersion: v1 kind: Namespace metadata: name: nfs-provisioner --- apiVersion: v1 kind: ServiceAccount metadata: name: nfs-subdir-external-provisioner namespace: nfs-provisioner --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: nfs-subdir-external-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"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: run-nfs-subdir-external-provisioner subjects: - kind: ServiceAccount name: nfs-subdir-external-provisioner namespace: nfs-provisioner roleRef: kind: ClusterRole name: nfs-subdir-external-provisioner-runner apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: leader-locking-nfs-subdir-external-provisioner namespace: nfs-provisioner rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: leader-locking-nfs-subdir-external-provisioner namespace: nfs-provisioner subjects: - kind: ServiceAccount name: nfs-subdir-external-provisioner namespace: nfs-provisioner roleRef: kind: Role name: leader-locking-nfs-subdir-external-provisioner apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: Deployment metadata: name: nfs-subdir-external-provisioner namespace: nfs-provisioner spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-subdir-external-provisioner template: metadata: labels: app: nfs-subdir-external-provisioner spec: serviceAccountName: nfs-subdir-external-provisioner containers: - name: nfs-subdir-external-provisioner image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: homelab.nas/nfs-subdir - name: NFS_SERVER value: 192.168.40.96 - name: NFS_PATH value: /volume1/samantha-private volumes: - name: nfs-client-root nfs: server: 192.168.40.96 path: /volume1/samantha-private --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nas-nfs provisioner: homelab.nas/nfs-subdir parameters: archiveOnDelete: "true" pathPattern: "${.PVC.annotations.nfs.io/storage-path}" reclaimPolicy: Retain volumeBindingMode: Immediate