跳转至

k8s使用NFS的几种方式

直接创建 NFS 的 Volume

直接创建 PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-imagenet
spec:
  capacity:
    storage: 150Gi
  volumeMode: Filesystem
  accessModes:
  - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  mountOptions:
  - vers=3
  - nolock
  - proto=tcp
  - rsize=1048576
  - wsize=1048576
  - hard
  - timeo=600
  - retrans=2
  - noresvport
  - nfsvers=4.1
  nfs:
    path: <YOUR_PATH_TO_DATASET>
    server: <YOUR_NFS_SERVER>

通过挂载 PVC 使用此 PV:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-imagenet
spec:
  accessModes:
  - ReadOnlyMany
  resources:
    requests:
      storage: 150Gi
  storageClassName: nfs

sig-storage-lib-external-provisioner

使用 sig-storage-lib-external-provisioner https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner 库开发 external provisioners

nfs-subdir-external-provisioner

(1)nfs-subdir-external-provisioner(nfs-client-provisioner)

是一个自动配置 P V程序,它必须使用已配置的 NFS 服务器来支持通过 PVC 动态配置 PV。

配置的 PV 名为 ${namespace-pvcname}-{$pvname}

仓库地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

SC 配置:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs     # 动态卷分配者名称,必须和上面创建的"provisioner"变量中设置的Name一致
parameters:
  archiveOnDelete: "false"

创建的 PVC 后,会自动创建 PV 并将其 .spec.nfs.path 配置成 NFS_PATH/${namespace-pvcname}-{$pvname}

如果不额外配置,PVC 删除后的回收策略默认是 Delete。此时会给 Pod 对应的文件夹名字前面加一个 archived 做归档。

通过给 nfs-client-provisioner 传送参数 archiveOnDelete: "false",不会做归档而是直接删除文件夹。

nfs-ganesha-server-and-external-provisioner

(2)nfs-ganesha-server-and-external-provisioner(nfs-provisioner)

仓库地址:https://github.com/kubernetes-sigs/nfs-ganesha-server-and-external-provisioner

nfs-provisioner 是一个 out-of-tree 的动态 provisioner

可以将主机上某个 Volume(必须是支持的文件系统)挂载到它的 /export 目录

StorageClass 中指定 provisioner 为 example.com/nfs 即可

SC 配置:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: example-nfs
provisioner: example.com/nfs   
mountOptions:
  - vers=4.1

NFS CSI Driver

NFS CSI Driver 是 K8s 官方提供的 CSI 示例程序,只实现了 CSI 的最简功能

这个插件驱动本身只提供了集群中的资源和 NFS 服务器之间的通信层,使用这个驱动之前需要 Kubernetes 集群 1.14 或更高版本和预先存在的 NFS 服务器。

  • Controller 由 CSI Plugin + csi-provisioner + liveness-probe 组成

  • node-server 由 CSI Plugin + liveness-probe + node-driver-registrar 组成

Fluid

通过 Fluid 项目来使用 NFS

不但可以像读取本地文件一样读取 NFS 中的文件,还可以享受内存加速效果。

详情可参考 https://github.com/fluid-cloudnative/fluid

总结

从实际使用上讲使用 nfs 作为存储卷并不是一个好的方式,使用中会遇到千奇百怪的问题,kubernetes 官方也不太推荐生产使用 nfs 提供存储卷,但是实际上有时候无可奈何的要去用,建议数据重要的服务使用分布式存储如 ceph 或者通过云厂商提供的 csi 挂载云盘作为存储卷,再不行就使用 local pv。

Nfs 作为存储卷的已知问题:

  • 不保证配置的存储。可以分配超过 NFS 共享的总大小。共享也可能没有足够的存储空间来实际容纳请求。
  • 未实施预配的存储限制。无论供应的大小如何,应用程序都可以扩展以使用所有可用存储。
  • 目前不支持任何形式的存储调整大小/扩展操作。您最终将处于错误状态:Ignoring the PVC: didn't find a plugin capable of expanding the volume; waiting for an external controller to process this PVC.

  • selfLink was empty 在 K8s 集群 v1.20 之前都存在,在 v1.20 之后被删除问题。

  • 还有可能引起 failed to obtain lock 和 input/output error 等问题,从而导致 Pod CrashLoopBackOff。此外,部分应用不兼容 NFS,例如 Prometheus 等。
名称 优缺点
nfs-ganesha-server-and-external-provisioner 提供 nfs 的 pod 出现问题时,pvc 无法使用 不推荐使用
NFS Subdir External Provisioner 只支持配置一个 nfs server 端 推荐使用
NFS CSI Driver 虽然功能上较简单,但是可以在存储类中配置 nfs server 端地址,较为灵活 推荐使用

NFS CSI Driver 可提供 NFS 动态分配器,支持动态分配存储卷,分配和回收存储卷过程简便,可对接一个或者多个 NFS 服务端。