找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3150

积分

0

好友

420

主题
发表于 4 小时前 | 查看: 4| 回复: 0

Kubernetes NFS动态存储架构示意图

本质: 你不再需要手动创建 PersistentVolume (PV),而是通过 StorageClass 和 Provisioner 自动生成

本文将详细介绍如何在 Kubernetes 集群中,使用 NFS 作为后端存储,结合 nfs-subdir-external-provisioner 这款官方推荐的 云原生 动态存储控制器,来实现 StorageClass 的动态存储功能。

前期准备:NFS服务器配置及客户端安装

首先,需要准备好 NFS 服务器,并确保所有 Kubernetes 节点都已安装 NFS 客户端工具。

  • NFS Server: 11.0.1.8
  • 共享目录: /data/nfs-server/sc

在 NFS 服务器上执行以下命令:

# 创建共享存储路径
mkdir -p /data/nfs-server/sc
chmod -R 777 /data/nfs-server/sc

echo “/data/nfs-server/sc *(rw,no_root_squash,sync)” >> /etc/exports
exportfs -r

1. 创建名称空间 (Namespace)

我们将所有相关资源部署在一个独立的名称空间中,便于管理。

# 名称空间资源清单
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# cat > 01-ns.yaml <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: nfs-provisioner
EOF

2. 创建 RBAC 授权

Provisioner 作为一个控制器 Pod,需要相应的权限来操作 Kubernetes 的存储资源(如 PV、PVC、StorageClass 等)。

# rbac资源清单
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# cat > 02-rbac.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: nfs-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-client-provisioner-runner
rules:
  - 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: [“endpoints“]
    verbs: [“get“, “list“, “watch“, “create“, “update“]
  - apiGroups: [““]
    resources: [“events“]
    verbs: [“create“, “update“, “patch“]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: nfs-provisioner
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
EOF

3. 部署 Provisioner (Deployment)

这里我们采用经典的 nfs-subdir-external-provisioner 方案,它是一个官方维护的控制器,能监听 PVC 请求并自动创建对应的 PV 目录。

注意: 以下 YAML 中的 NFS 服务器 IP 和共享路径需要根据你的实际环境修改。

# deploy资源清单
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy.yaml]
# cat > 03-deploy.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: nfs-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/google_containers/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: dinginx/nfs
            - name: NFS_SERVER
              value: 11.0.1.8   #⚠️ 修改你的 NFS IP
            - name: NFS_PATH
              value: /data/nfs-server/sc #⚠️ 修改存储目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 11.0.1.8   #⚠️ 修改你的 NFS IP
            path: /data/nfs-server/sc #⚠️ 修改存储目录
EOF

4. 创建动态存储类 (StorageClass)

StorageClass 是动态存储的核心,它定义了使用哪个 Provisioner 以及创建 PV 时的参数。

# 创建sc资源清单
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy.yaml]
# cat > 04-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-sc
# provisioner: fuseim.pri/ifs # or choose another name, must match deployment‘s env PROVISIONER_NAME’
provisioner: dinginx/nfs
parameters:
# 注意哈,仅对“reclaimPolicy: Delete“时生效,如果回收策略是“reclaimPolicy: Retain”,则无视此参数!
# 如果设置为false,删除数据后,不会在存储卷路径创建“archived-*”前缀的目录哟!
# archiveOnDelete: “false”
# 如果设置为true,删除数据后,会在存储卷路径创建“archived-*”前缀的目录哟
  archiveOnDelete: “true”
# 声明PV回收策略,默认值为Delete
reclaimPolicy: Retain
volumeBindingMode: Immediate
EOF

5. 创建 PVC 进行测试

现在我们可以创建一个 PersistentVolumeClaim (PVC) 来触发动态供给流程。

# 编写测试PVC资源清单
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy.yaml]
# cat > 05-pvc.yaml <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dinginx-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-sc
  resources:
    requests:
      storage: 1Gi
EOF

6. 创建所有资源并验证

将前面创建的所有 YAML 文件应用,并查看资源状态。

# 创建所有资源
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl apply -f .

# 查看资源
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl -n nfs-provisioner get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-7ccdbfcf8c-bpbpj   1/1     Running   0          5m6s
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl apply -f 05-pvc.yaml 
persistentvolumeclaim/dinginx-pvc created
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-e7a0be94-faa3-4f61-8917-78a1d91a8dd0   1Gi        RWX            Retain           Bound      default/dinginx-pvc   nfs-sc         <unset>                          4s

NAME                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/dinginx-pvc   Bound    pvc-e7a0be94-faa3-4f61-8917-78a1d91a8dd0   1Gi        RWX            nfs-sc         <unset>                 4s

可以看到,一个名为 dinginx-pvc 的 PVC 已经创建成功,并且系统自动创建了一个对应的 PV 与之绑定。

7. 创建一个 Deployment 来使用这个 PVC

让我们创建一个应用 Deployment,将上一步创建的 PVC 挂载到其 Pod 中。

# 创建deploy资源清单
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# cat 06-deploy-pvc.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dinginx-deploy-pvc001
spec:
  replicas: 3
  selector:
    matchLabels:
      app: dinginx001
  template:
    metadata:
      labels:
        app: dinginx001
    spec:
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: dinginx-pvc
      containers:
      - name: shop01
        image: harbor.dinginx.org/global-shopping/global-shopping:v4
        volumeMounts:
        - name: data
          mountPath: /dinginx-pvc

8. 测试数据持久性

启动应用,并在容器内创建测试数据,然后删除资源以验证数据是否会丢失。

# 查看资源
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
dinginx-deploy-pvc001-5986bff9d7-4vzm9   1/1     Running   0          6s
dinginx-deploy-pvc001-5986bff9d7-7r7k5   1/1     Running   0          6s
dinginx-deploy-pvc001-5986bff9d7-dqcjp   1/1     Running   0          6s

# 进到容器生成测试数据
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl exec -it pods/dinginx-deploy-pvc001-5986bff9d7-4vzm9 -- bash
root@dinginx-deploy-pvc001-5986bff9d7-4vzm9:/usr/share/nginx/html
# cd
root@dinginx-deploy-pvc001-5986bff9d7-4vzm9:~
# ls /dinginx-pvc/
root@dinginx-deploy-pvc001-5986bff9d7-4vzm9:~
# mkdir /dinginx-pvc/dinginx
root@dinginx-deploy-pvc001-5986bff9d7-4vzm9:~
# cd /dinginx-pvc/dinginx/
root@dinginx-deploy-pvc001-5986bff9d7-4vzm9:/dinginx-pvc/dinginx
# touch SUCCESSED 
root@dinginx-deploy-pvc001-5986bff9d7-4vzm9:/dinginx-pvc/dinginx
# exit
exit

# nfs服务端测试数据
[root@harbor-club /data/nfs-server/sc]
# tree default-dinginx-pvc-pvc-81a0a868-7b0a-49c1-936a-f712979e1051
default-dinginx-pvc-pvc-81a0a868-7b0a-49c1-936a-f712979e1051
└── dinginx
    └── SUCCESSED

1 directory, 1 file

# 验证删除pod资源,数据不会丢失
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl delete -f 05-pvc.yaml -f 06-deploy-pvc.yaml 
persistentvolumeclaim “dinginx-pvc” deleted from default namespace
deployment.apps “dinginx-deploy-pvc001” deleted from default namespace
[root@k8s-master01 /data/manifests/project/06-nfs-pvc-deploy]
# kubectl get pvc,po
No resources found in default namespace.

# nfs服务端验证数据未丢失
[root@harbor-club /data/nfs-server/sc]
# tree default-dinginx-pvc-pvc-81a0a868-7b0a-49c1-936a-f712979e1051 ; date
default-dinginx-pvc-pvc-81a0a868-7b0a-49c1-936a-f712979e1051
└── dinginx
    └── SUCCESSED

1 directory, 1 file
Wed Apr 15 05:50:36 CST 2026

如上所示,即使在 Kubernetes 中删除了 PVC 和应用 Pod,存储在 NFS 服务器上的数据依然完好无损。这得益于我们在 StorageClass 中设置的 reclaimPolicy: Retain 策略。

总结

通过以上步骤,我们成功地在 Kubernetes 中搭建了一套基于 NFS 的动态存储方案。这套方案极大地简化了持久化存储的管理,开发者只需声明所需存储的容量和访问模式(通过 PVC),系统就能自动按需创建 PV,非常适合在 DevOps 流程和需要频繁创建有状态应用的场景中使用。如果你想探索更多类似的 云原生 存储方案或与其他开发者交流实践经验,欢迎访问云栈社区进行深度讨论。




上一篇:Claude Code手机端远程控制方案对比:官方、社区与自托管选哪个?
下一篇:得物社区生成式召回技术解析:基于Transformer的落地实践与AB测试效果
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-19 09:36 , Processed in 0.982391 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表