Kubernetes NFS 接入方案

一、整体架构与流程概览

vbscript 复制代码
┌────────────────────────────────────────────────────────────┐
│                    Kubernetes 集群                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  StorageClass (nfs-csi)                             │   │
│  │    provisioner: nfs.csi.k8s.io                      │   │
│  │    parameters: server, share                        │   │
│  └───────────────────┬─────────────────────────────────┘   │
│                      │ 动态创建                             │
│                      ▼                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  PVC (用户申请)  ──绑定──►  PV (自动创建)             |   │
│  └───────────────────┬─────────────────────────────────┘   │
│                      │ 挂载                                │
│                      ▼                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Pod ── 通过 CSI 驱动 ──►  NFS Server                │   │
│  └─────────────────────────────────────────────────────┘   │
└────────────────────────────────────────────────────────────┘
                              │
                              ▼
                    ┌─────────────────┐
                    │   NFS Server    │
                    │ 192.168.100.13  │
                    │ /exports/share  │
                    └─────────────────┘

核心概念

  • CSI (Container Storage Interface) :Kubernetes 的存储插件标准,让存储厂商可以按统一方式接入
  • NFS CSI Driver:实现了 CSI 接口的 NFS 驱动,能在 PVC 创建时自动在 NFS 服务器上创建子目录作为 PV
  • StorageClass:定义存储的"模板",指定使用哪个驱动、NFS 服务器地址等参数

二、使用场景

NFS 作为共享文件系统,适合以下场景 :

场景 说明 访问模式
多 Pod 共享数据 多个 Pod 同时读写同一份数据,如内容管理系统、文件服务 ReadWriteMany
日志收集 多个 Pod 将日志写入共享存储,统一采集 ReadWriteMany
Web 应用内容 静态网站文件存储在 NFS 上,多个 Web Pod 同时挂载 ReadWriteMany
数据分析 数据预处理、AI 训练数据集共享 ReadWriteMany
CI/CD 构建产物 多个构建任务共享输出目录 ReadWriteMany

注意:NFS 不适合高 IOPS 的数据库场景(如 MySQL、PostgreSQL),建议使用本地 SSD 或块存储。

如:多个 Pod 写入同一个共享目录,再由 Sidecar 或 DaemonSet 统一采集:

css 复制代码
┌─────────────────────────────────────────────────────┐
│  应用 Pod A ──┐                                     │
│  应用 Pod B ──┼──► 共享 NFS 卷 (/var/log/app)        │
│  应用 Pod C ──┘              │                      │
│                              ▼                      │
│                    日志采集器 (Fluentd/Filebeat)     │
│                              │                      │
│                              ▼                      │
│                      Elasticsearch / S3             │
└─────────────────────────────────────────────────────┘

生产优势:采集器只挂载一个 NFS 路径即可收集所有 Pod 的日志,避免每个 Pod 单独配置日志采集。

三、前置准备

1. 准备 NFS 服务器

你需要有一台已配置好的 NFS 服务器,并且所有 K8s 节点都能访问它 。

服务端配置示例(以 192.168.100.13 为例):

bash 复制代码
# 安装 NFS 服务
yum install -y nfs-utils rpcbind   # CentOS/RHEL/Rocky
# 或 apt install -y nfs-kernel-server  # Ubuntu
​
# 创建共享目录
mkdir -p /data/nfs
chmod 755 /data/nfs
​
# 配置 exports
echo "/data/nfs 192.168.100.0/24(rw,sync,no_root_squash,no_subtree_check)" >> /etc/exports
​
# 启动服务
systemctl start rpcbind nfs-server
systemctl enable rpcbind nfs-server
​
# 验证
showmount -e localhost
​
结果:
    Export list for localhost:
    /data/nfs 192.168.100.0/24

2. 确保节点安装 NFS 客户端

所有 K8s 工作节点(work)安装 nfs-utils,否则挂载会失败(如果控制节点没打污点也需要安装) :

bash 复制代码
# CentOS/RHEL
yum install -y nfs-utils
​
# Ubuntu
apt install -y nfs-common

四、完整操作流程

步骤 1:安装 NFS CSI Driver

yaml 复制代码
#在你的K8S集群运行:
curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.11.0/deploy/install-driver.sh | bash -s v4.11.0 --
​
​
#如果你的服务器无法访问这个地址,人么办?
#例如本人的服务器环境就无法访问😢,不过没关系,你只要能搞下来这个脚本就好。比如迅雷,野生加速网站等👌,以下是风骚操作:
# 1 迅雷下载脚本
# 2 rz上传到服务器 
ls install-driver.sh
sh install-driver.sh v4.11.0
#欸? 这里执行又失败了,打开脚本看看。原来yaml文件也是要在raw.githubusercontent.com下载
# 编辑脚本:
vim install-driver.sh
​
---
if [ $ver != "master" ]; then
  repo="$repo/$ver"
fi
​
repo="https://gh-proxy.org/"$repo        #在此处加入这一行。使用野生加速网站
​
echo "Installing NFS CSI driver, version: $ver ..."
kubectl apply -f $repo/rbac-csi-nfs.yaml
kubectl apply -f $repo/csi-nfs-driverinfo.yaml
---
​
sh install-driver.sh
#这下就把yaml正常加载了
#但是还没完... 你会发现镜像又下载不下来。目前免费的镜像加速网站几乎绝种了。怎么办?
#那只能是找一台云服务器或科学上网用docker拉取镜像下载下来,再导到harbor或者直接到本机了。
#比如本人使用的csi-driver-nfs v4.11.0,需要的镜像有:
---
registry.k8s.io/sig-storage/csi-resizer         v2.1.0      589e525cddef    12 hours ago    linux/amd64    94.02MB    37.25MB
registry.k8s.io/sig-storage/csi-snapshotter     v8.5.0      da081c27e8a6    12 hours ago    linux/amd64    94.39MB    37.29MB
registry.k8s.io/sig-storage/csi-node-driver-registrar    v2.16.0     ab482308a492    12 hours ago    linux/amd64    30.21MB    14.11MB
gcr.io/k8s-staging-sig-storage/nfsplugin        canary      eb3733a6070b    12 hours ago    linux/amd64    161.8MB    56.32MB
registry.k8s.io/sig-storage/livenessprobe       v2.18.0     c4cc074199c0    12 hours ago    linux/amd64    30.43MB    14.22MB
registry.k8s.io/sig-storage/csi-provisioner     v6.2.0      6be9f63ca4ca    12 hours ago    linux/amd64    102.4MB    39.52MB
---
​
# docker下载镜像导出:
docker pull registry.k8s.io/sig-storage/csi-resize:v2.1.0
docker save -o csi-resize.tgz registry.k8s.io/sig-storage/csi-resize:v2.1.0
# 如果你用的是containerd, 用nerdctl 导入:
nerdctl -n k8s.io load -i csi-resize.tgz
# 如果你有harbor仓库的话会方便一点,如果没有需要每台node都导入,最后:
kubectl  get pod -n kube-system | grep nfs
csi-nfs-controller-675cf9f6c9-n7kz8        5/5     Running   0              11m
csi-nfs-node-5mznd                         3/3     Running   0              13m
csi-nfs-node-7ch8j                         3/3     Running   0              13m
csi-nfs-node-hg86g                         3/3     Running   0              12m
csi-nfs-node-qj6fc                         3/3     Running   0              13m
csi-nfs-node-sp8v4                         3/3     Running   0              12m

步骤 2:创建 StorageClass

这是关键配置,告诉 Kubernetes 如何使用 NFS 动态创建存储

创建 sc-nfs.yaml

yaml 复制代码
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
provisioner: nfs.csi.k8s.io     # 指定使用 NFS CSI 驱动
parameters:
  server: 192.168.100.13        # 替换为你的 NFS 服务器 IP
  share: /data/nfs              # NFS 共享路径
    mountPermissions: '0777'    # 指定文件权限
  # subDir: ${pvc.name}         # 可选:自动创建子目录命名规则
mountOptions:
  - nfsvers=4.2                 # NFS 协议版本 (这里需要再nfs服务器查看支持的版本:cat /proc/fs/nfsd/versions )
  - hard                        # 硬挂载,失败时持续重试
  - noatime                     # 不更新访问时间,提升性能
reclaimPolicy: Retain           # PVC 删除时保留后端数据 ,如果Delete就是不保留
volumeBindingMode: Immediate    # PVC 创建后立即尝试绑定符合条件的 PV
arduino 复制代码
kubectl get sc
NAME      PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-csi   nfs.csi.k8s.io   Retain          Immediate           false                  16s

参数说明

  • server:NFS 服务器地址(必填)
  • share:NFS 共享根路径(必填)
  • subDir:可选,自定义子目录命名规则,默认使用 pvc-{namespace}-{name}
  • mountOptions:挂载选项,可指定 NFS 协议版本、超时策略等

步骤 3:创建 PVC(PersistentVolumeClaim)

用户创建 PVC 申请存储,系统会自动创建对应的 PV 。

创建 pvc.yaml

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-demo-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteMany          # 支持多 Pod 同时读写(多路读写)
  storageClassName: nfs-csi  # 使用上面创建的 StorageClass
  resources:
    requests:
      storage: 5Gi          # 申请 5GB 空间

验证:

swift 复制代码
[root@vm-100-11 pv]# kubectl  apply  -f pvc.yaml 
persistentvolumeclaim/nfs-demo-pvc created
[root@vm-100-11 pv]# kubectl  get pvc 
NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
nfs-demo-pvc   Bound    pvc-4524298a-aa5e-4574-90b6-9f76f73207d7   5Gi        RWX            nfs-csi        <unset>                 9s
[root@vm-100-11 pv]# kubectl  get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-4524298a-aa5e-4574-90b6-9f76f73207d7   5Gi        RWX            Retain           Bound    default/nfs-demo-pvc   nfs-csi        <unset>                          15s

关键点

  • PVC 状态变为 Bound 表示绑定成功
  • PV 是自动创建的,名称格式为 pvc-{uuid}
  • 在 NFS 服务器上会自动创建一个子目录(路径:/data/nfs/share/pvc-abc123...

步骤 4:在 Pod 中使用 PVC

创建 pod.yaml 挂载 PVC:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: nfs-test-pod
spec:
  containers:
  - name: app
    image: nginx:alpine
    volumeMounts:
    - name: persistent-storage
      mountPath: /usr/share/nginx/html   # 容器内挂载路径
    ports:
    - containerPort: 80
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: nfs-demo-pvc            # 引用上面创建的 PVC

部署测试:

bash 复制代码
kubectl  apply -f pod.yaml 
kubectl exec nfs-test-pod -- sh -c "echo 'Hello NFS' > /usr/share/nginx/html/test.txt"
# 在 NFS 服务器上验证文件已创建
# 预期在 /data/nfs/pvc-xxx/test.txt 中看到内容

步骤 5:Deployment 共享同一个 PVC 的配置

  • 使用的 StorageClass 或 PVC 必须支持 ReadWriteMany(NFS-CSI 默认支持)
  • 所有 Pod 副本需要读写同一份数据时,应用需能处理并发访问(如文件锁、数据库锁等)
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-shared
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-shared
  template:
    metadata:
      labels:
        app: nginx-shared
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        volumeMounts:
        - name: shared-storage
          mountPath: /usr/share/nginx/html   # 所有容器共享此目录
        ports:
        - containerPort: 80
      volumes:
      - name: shared-storage
        persistentVolumeClaim:
          claimName: nfs-demo-pvc           # 所有 Pod 共用同一个 PVC

验证:

sql 复制代码
kubectl  apply  -f testpvc-depolyment.yaml  
​
[root@vm-100-11 pv]# kubectl  get pods  -l app=nginx-shared
NAME                            READY   STATUS    RESTARTS   AGE
nginx-shared-796bb49fdb-5t9fj   1/1     Running   0          94s
nginx-shared-796bb49fdb-cr7dn   1/1     Running   0          94s
nginx-shared-796bb49fdb-r9qqg   1/1     Running   0          94s
[root@vm-100-11 pv]# kubectl  get pods  -l app=nginx-shared -o wide
 NAME                            READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
nginx-shared-796bb49fdb-5t9fj   1/1     Running   0          99s   10.1.12.144   vm-100-22   <none>           <none>
nginx-shared-796bb49fdb-cr7dn   1/1     Running   0          99s   10.1.10.145   vm-100-21   <none>           <none>
nginx-shared-796bb49fdb-r9qqg   1/1     Running   0          99s   10.1.12.145   vm-100-22   <none>           <none>
[root@vm-100-11 pv]#  curl 10.1.12.144/test.txt
Hello NFS
[root@vm-100-11 pv]#  curl 10.1.12.145/test.txt
Hello NFS
[root@vm-100-11 pv]#  curl 10.1.10.145/test.txt
Hello NFS

五、完整流程图

yaml 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    1. 环境准备                                   │
│  ┌──────────────┐     ┌──────────────────────────────────────┐  │
│  │ NFS Server   │────▶│ 所有 Worker 节点安装 nfs-utils       │  │
│  │192.168.100.13│     └──────────────────────────────────────┘  │
│  └──────────────┘                                               │
└─────────────────────────────────────────────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    2. 安装 NFS CSI Driver                        │
│  kubectl create -f https://raw.githubusercontent.com/...        │
│  或 helm install ...                                             │
└─────────────────────────────────────────────────────────────────┘
                              ▼
┌────────────────────────────────────────────────────────────────┐
│                    3. 创建 StorageClass                         │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ apiVersion: storage.k8s.io/v1                            │  │
│  │ kind: StorageClass                                       │  │
│  │ metadata: name: nfs-csi                                  │  │
│  │ provisioner: nfs.csi.k8s.io                              │  │
│  │ parameters: server: 192.168.100.13, share: /data/nfs/    │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘
                              ▼
┌────────────────────────────────────────────────────────────────┐
│                    4. 创建 PVC                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ PVC: nfs-demo-pvc (storage: 5Gi)                        │  │
│  │                    │                                     │  │
│  │                    ▼ 自动绑定                             │  │
│  │ PV: pvc-xxx (自动创建)                                    │  │
│  │      │                                                   │  │
│  │      ▼ 在 NFS 服务器上创建子目录                           │  │
│  │ /data/nfs/pvc-xxx/                                       │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘
                              ▼
┌────────────────────────────────────────────────────────────────┐
│                    5. Pod 挂载使用                              │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ Pod: nginx                                               │  │
│  │   volumes: persistentVolumeClaim: nfs-demo-pvc           │  │
│  │   volumeMounts: mountPath: /usr/share/nginx/html         │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘
​

六、常见问题与注意事项

1. 挂载失败:no such file or directory

  • 检查 NFS 服务器地址和共享路径是否正确
  • 确认所有节点都能 showmount -e <server> 看到共享

2. Pod 启动报错:bad option; need /sbin/mount.nfs

  • 工作节点未安装 nfs-utils,执行 yum install -y nfs-utils

3. 权限问题:无法写入文件

  • 检查 NFS 服务端的 /etc/exports 中的 no_root_squash 配置
  • 或在 StorageClass 的 mountOptions 中添加 no_root_squash

4. 协议版本降级

  • 如果 NFS 服务端不支持 nfsvers=4.2,会自动降级到低版本
  • 可在服务端执行 cat /proc/fs/nfsd/versions 确认支持的版本

5. reclaimPolicy: Delete 会删除数据

  • PVC 删除时,后端 NFS 子目录也会被删除
  • 如需保留数据,修改 StorageClass 中的 reclaimPolicy: Retain

七、总结

组件 作用 配置要点
NFS Server 提供底层存储 确保所有 K8s 节点可访问,exports 配置正确
CSI Driver 实现存储插件接口 安装 nfs.csi.k8s.io 驱动
StorageClass 定义存储模板 配置 NFS 服务器地址、共享路径、挂载选项
PVC 用户申请存储 指定 StorageClass 名称和容量
Pod 使用存储 通过 volumes.persistentVolumeClaim 引用 PVC

企业级架构方案

生产环境中,NFS 服务器本身不能是单点故障。常见的高可用方案:

方案 说明
Keepalived + NFS 多台 NFS 服务器通过 VIP 提供主备切换
CephFS + NFS-Ganesha 底层使用 CephFS,通过 NFS 网关暴露,支持快照和克隆
云厂商托管 NFS 如 AWS EFS、Azure Files、阿里云 NAS,自带高可用

生产建议:

考量维度 建议
网络带宽 确保 NFS 网络接口有足够带宽,或使用专用 NIC 隔离流量,避免与其他网络争抢
CPU 资源 NFS 网关的 CPU 利用率随共享数量增加而上升,需预留足够资源
故障切换窗口 高可用 NFS 发生主备切换时,通常有几分钟的故障转移窗口,应用需能容忍这个时间

协议版本选择

NFS 版本 生产建议
NFSv4.1/v4.2 推荐使用,支持更强安全特性、状态协议、性能优化
NFSv3 降级选项,如果后端仅支持 v3 时可用

安全配置

根据生产实践,NFS 共享需要关注以下安全维度:

安全维度 生产推荐配置
NFS Export 权限 rw,sync,root_squash 限制 root 写入(而非 no_root_squash
容器用户 避免使用 root,配置 securityContext.runAsUserfsGroup
子目录隔离 不同项目使用不同的 PVC,或通过 subPath 隔离
访问控制 配合 RBAC + PVC scope + namespace 实现租户隔离

场景总结

场景类型 是否推荐 NFS-CSI 原因
静态内容服务(多副本 Web) ✅ 强烈推荐 天然支持 ReadWriteMany,内容更新方便
日志/指标采集 ✅ 推荐 统一存储路径,简化采集架构
AI 模型加载 ✅ 推荐 多 Pod 共享只读模型,节省存储空间
数据处理流水线 ✅ 推荐 解耦生产者和消费者
开发测试环境 ✅ 推荐 动态供给,自动化管理
高吞吐数据库 ❌ 不推荐 NFS 网络延迟和锁机制不适合 OLTP 场景
需要强一致性锁的场景 ⚠️ 谨慎 应用需自行处理并发写入冲突
相关推荐
河码匠5 小时前
Kubernetes YAML 详解之网络服务二( Ingress、IngressClasses)
云原生·容器·kubernetes
blackorbird5 小时前
一个来自法国的基于K8s的规模化扫描集群
云原生·容器·kubernetes
掘根5 小时前
【微服务即时通讯】消息存储子服务2
微服务·云原生·架构
风向决定发型丶6 小时前
浅谈K8S的Label和Annotation
云原生·容器·kubernetes
培小新6 小时前
【Docker安全优化】
云原生·eureka
easy_coder6 小时前
从 ManifestRender 到 Certificate:一次 Kubernetes 应用发布故障的深度排障实录
云原生·云计算
拦路雨g6 小时前
Duboo配置zookeeper账号密码认证链接
分布式·zookeeper·云原生
倔强的胖蚂蚁6 小时前
openEuler 24.03 LTS SP3 使用指南
运维·云原生
上海云盾-小余7 小时前
云原生环境下 DDoS 防御升级:弹性清洗与智能调度实战方案
云原生·ddos