kubeasz 集群存储实战:基于 PV/PVC、NFS 动态供应与 Local Path 本地存储的完整配置指南
2026/9/15 16:57:23 网站建设 项目流程

kubeasz 集群存储实战:基于 PV/PVC、NFS 动态供应与 Local Path 本地存储的完整配置指南

【免费下载链接】kubeasz使用Ansible脚本安装K8S集群,介绍组件交互原理,方便直接,不受国内网络环境影响项目地址: https://gitcode.com/GitHub_Trending/ku/kubeasz

导读

本文以 kubeasz 项目中的集群存储章节(对应 docs/setup/08-cluster-storage.md)为核心骨架,系统讲解 Kubernetes 中 PV(PersistentVolume)、PVC(PersistentVolumeClaim)两类存储抽象的概念与协作方式,并深入介绍 kubeasz 集成的两种存储供应者(provisioner):nfs-subdir-external-provisioner(NFS 存储目录供应者)与local-path-provisioner(本地存储目录供应者)。读完本文,你将掌握:如何手写静态 PV 并绑定 PVC;如何通过编辑集群配置文件一键启用动态 PV 供应;如何在 NFS 服务器侧验证自动创建的挂载目录;以及如何为 I/O 密集型应用配置本地 SSD 目录存储。

一、存储抽象:PV 与 PVC

在 Kubernetes 中,存储被抽象为两个核心资源对象:

  • PV(PersistentVolume):集群层面的存储资源,由管理员预先创建(静态供应),或由存储供应者按需动态创建(动态供应)。它独立于任何 Pod 存在,生命周期与集群一致。
  • PVC(PersistentVolumeClaim):用户对存储资源的"请求"(需求声明),它指定容量、访问模式与存储类(StorageClass)。PVC 与满足条件的 PV 绑定后,Pod 即可通过 volume 引用 PVC 来使用存储。

PV 是集群中的资源,PVC 是对这些资源的请求。

从设计上看,PV 和 PVC 都是抽象概念,真正的存储能力由 Kubernetes 的卷插件(volume plugin)提供。当前 Kubernetes 生态中支持 NFS、iSCSI 以及各大云厂商提供的存储系统,具体访问模式等细节可参考 Kubernetes 官方持久卷文档(Persistent Volumes 概念页的 Access Modes 章节)。访问模式(AccessModes)是 PVC/PV 匹配的关键字段之一,常见取值包括:

| 访问模式 | 含义 | 典型场景 | | :- | :- | :- | | ReadWriteOnce(RWO) | 单节点读写 | 单副本数据库、本地卷 | | ReadOnlyMany(ROX) | 多节点只读 | 配置共享、只读数据分发的副本 | | ReadWriteMany(RWX) | 多节点读写 | 共享文件存储(NFS/CephFS)、EFK 日志汇聚 |

在 kubeasz 项目中,存储相关能力统一归入cluster-addon角色管理(见 roles/cluster-addon/tasks/main.yml),通过 playbook playbooks/07.cluster-addon.yml 在localhost上执行安装。其中与存储直接相关的两个任务文件分别是:

  • roles/cluster-addon/tasks/nfs-provisioner.yml:渲染并应用 NFS provisioner 部署清单;
  • roles/cluster-addon/tasks/local-storage.yml:渲染并应用 local-path provisioner 部署清单。

二者均受配置开关控制(nfs_provisioner_install/local_path_provisioner_install"yes"时生效),且主任务会根据集群中是否已存在对应 Pod 决定是否重复安装(幂等保护)。

二、NFS 存储目录供应者

NFS(Network File System)允许系统将本地目录共享给网络上的其他系统,用户和应用程序可以像访问本地文件一样访问远程文件。它是搭建共享读写(RWX)持久化存储最常用的方案之一。使用 NFS 动态供应前,需要先准备一台可用的 NFS 服务器。

2.1 准备 NFS 服务器

kubeasz 仓库提供了完整的 NFS 服务器搭建指南 docs/guide/nfs-server.md,核心步骤概括如下:

  1. 安装服务端(以 Ubuntu 为例):

    apt install nfs-kernel-server
  2. 配置共享目录:编辑/etc/exports,每个共享目录独占一行,格式为NFS共享目录路径 客户机IP或名称(参数1,参数2,...)。例如:

    /share 192.168.1.0/24(rw,sync,insecure,no_subtree_check,no_root_squash)
  3. 启动服务

    systemctl start nfs-kernel-server.service

关于/etc/exports参数,仓库文档给出了完整对照表,常用关键参数如下:

| 参数 | 说明 | | :- | :- | | ro / rw | 只读 / 读写访问 | | sync / async | 所有数据在请求时写入共享 / nfs 在写入数据前可以响应请求 | | insecure | nfs 通过 1024 以上的端口发送(必须加,否则客户端挂载报错mount.nfs: access denied by server while mounting) | | no_subtree_check | 不检查父目录权限 | | no_root_squash | root 用户具有根目录的完全管理访问权限 |

两个实战提示(源自仓库文档):一是尽量使用主机名/IP/IP 段做最小化授权;二是在 k8s 集群中配合 nfs-client-provisioner 使用时,/etc/exports需要放行Pod 的网段(IP 段),否则 provisioner Pod 会因mount.nfs: access denied by server while mounting而无法启动。

2.2 静态 PV:手动创建持久卷

当存储规模小、PVC 数量有限时,管理员可以手动创建 PV 供 PVC 绑定。原文档给出了一个典型的 NFS 静态 PV 示例:

apiVersion: v1 kind: PersistentVolume metadata: name: pv-es-0 spec: capacity: storage: 4Gi accessModes: - ReadWriteMany volumeMode: Filesystem persistentVolumeReclaimPolicy: Recycle storageClassName: "es-storage-class" nfs: # 根据实际共享目录修改 path: /share/es0 # 根据实际 nfs服务器地址修改 server: 192.168.1.208

各字段的作用与注意事项:

  • capacity.storage:PV 声明的容量(如4Gi),PVC 的容量请求必须小于等于该值才可能完成绑定;
  • accessModes:访问模式,此处ReadWriteMany允许多个节点同时读写,是 NFS 的典型用法;
  • volumeMode: Filesystem:卷模式为文件系统(另一可选值为Block原始块设备);
  • persistentVolumeReclaimPolicy: Recycle:PVC 释放后 PV 的回收策略,可选Retain(保留)、Recycle(回收清空后重新可用)或Delete(动态供应时删除底层存储);
  • storageClassName:PV 归属的存储类。PVC 声明相同storageClassName时才会与它匹配绑定;
  • nfs.path / nfs.server:NFS 共享的实际路径与服务器地址,需要按真实环境修改。

创建该 PV 后,再创建同storageClassName的 PVC,即可完成绑定使用(具体可参考后文 test-pod 例子中的 PVC 写法)。

2.3 动态 PV:通过 StorageClass 自动供应

在生产集群中,PVC 请求数量会非常多,如果每次都需要管理员手动创建 PV 会非常繁琐。Kubernetes 提供了多种provisioner来动态创建 PV:管理员只需定义好 StorageClass(存储类),当用户提交 PVC 时,provisioner 会自动为其创建对应的 PV,并将不同存储类型封装成不同 StorageClass 供 PVC 按需选用,既节省了管理员的时间,又实现了存储能力的按需分配。

kubeasz 集成的 NFS 动态供应方案是nfs-subdir-external-provisioner(对应 roles/cluster-addon/templates/nfs-provisioner/nfs-provisioner.yaml.j2)。其部署清单主要由四部分组成:

  1. ServiceAccount + ClusterRole/ClusterRoleBinding:为 provisioner 授权 PV/PVC/StorageClass 的增删改查与事件上报权限;
  2. Role/RoleBinding(leader-locking):在同一命名空间内通过 endpoints 做选主(leader election),保证多个副本并发时只有一个 provisioner 在真正工作;
  3. Deployment:以 NFS 卷挂载方式运行nfs-client-provisioner容器,通过环境变量注入PROVISIONER_NAMEk8s-sigs.io/nfs-subdir-external-provisioner)、NFS_SERVERNFS_PATH
  4. StorageClass:声明 provisioner 名称与供应参数。

其中 StorageClass 定义如下(模板节选):

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: {{ nfs_storage_class }} # 默认 managed-nfs-storage provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: archiveOnDelete: "false" # 删除 PVC 时直接删除对应 NFS 目录,不做归档
在 kubeasz 中启用 NFS 动态供应

步骤 1:编辑集群配置文件clusters/${集群名}/config.yml

找到 cluster-addon 相关参数段(默认值见 example/config.yml),修改为:

# 在 cluster-addon 中启用 nfs-provisioner 安装 nfs_provisioner_install: "yes" # 修改为 yes nfs_provisioner_namespace: "kube-system" # provisioner 部署的命名空间 nfs_provisioner_ver: "v4.0.1" # 镜像版本,由 ezdown 下载并写入实际版本号 nfs_storage_class: "managed-nfs-storage" # 生成的 StorageClass 名称 nfs_server: "192.168.31.244" # 修改为实际 nfs server 地址 nfs_path: "/data/nfs" # 修改为实际的 nfs 共享目录

各参数的说明:

| 参数 | 默认值 | 说明 | | :- | :- | :- | |nfs_provisioner_install|no| 是否安装 nfs provisioner,改为yes启用 | |nfs_provisioner_namespace|kube-system| provisioner 部署所在命名空间 | |nfs_provisioner_ver| 模板变量 | provisioner 镜像版本,安装脚本按下载产物自动填充 | |nfs_storage_class|managed-nfs-storage| 生成的 StorageClass 名称,供 PVC 引用 | |nfs_server|192.168.1.10| NFS 服务器地址,必须改为实际地址 | |nfs_path|/data/nfs| NFS 共享目录,必须改为实际共享路径 |

步骤 2:创建 nfs provisioner

$ dk ezctl setup ${集群名} 07

ezctl setup ${集群名} 07对应执行 playbooks/07.cluster-addon.yml 中的 cluster-addon 角色,其内部会依次渲染 NFS provisioner 部署清单与测试 Pod 清单(见 roles/cluster-addon/tasks/nfs-provisioner.yml),并将产物写入clusters/${集群名}/yml/nfs-provisioner/,最后通过kubectl apply创建资源。

执行成功后验证:

$ kubectl get pod --all-namespaces | grep nfs-client kube-system nfs-client-provisioner-84ff87c669-ksw95 1/1 Running 0 21m

步骤 3:验证动态 PV 的使用

kubeasz 在clusters/${集群名}/yml/nfs-provisioner/目录下生成了测试例子test-pod.yaml(模板见 roles/cluster-addon/templates/nfs-provisioner/test-pod.yaml.j2),其内容包含一个 PVC 和一个挂载该 PVC 的 busybox 测试 Pod:

kind: PersistentVolumeClaim apiVersion: v1 metadata: name: test-claim spec: storageClassName: {{ nfs_storage_class }} # 引用 managed-nfs-storage accessModes: - ReadWriteMany resources: requests: storage: 2Mi --- kind: Pod apiVersion: v1 metadata: name: test-pod spec: containers: - name: test-pod image: busybox command: ["/bin/sh"] args: ["-c", "touch /mnt/SUCCESS && exit 0 || exit 1"] volumeMounts: - name: nfs-pvc mountPath: "/mnt" restartPolicy: "Never" volumes: - name: nfs-pvc persistentVolumeClaim: claimName: test-claim

应用测试清单并验证:

$ kubectl apply -f /etc/kubeasz/clusters/hello/yml/nfs-provisioner/test-pod.yaml # 验证测试 pod(写入 SUCCESS 后退出,状态为 Completed) kubectl get pod NAME READY STATUS RESTARTS AGE test-pod 0/1 Completed 0 6h36m # 验证自动创建的 pv 资源 kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-44d34a50-e00b-4f6c-8005-40f5cc54af18 2Mi RWX Delete Bound default/test-claim managed-nfs-storage 6h36m # 验证 PVC 已经绑定成功:STATUS 字段为 Bound kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-claim Bound pvc-44d34a50-e00b-4f6c-8005-40f5cc54af18 2Mi RWX managed-nfs-storage 6h37m

从输出可以看出:PVC 提交后 provisioner 自动创建了名为pvc-44d34a50-...的 PV,其回收策略为Delete(动态供应的 PV 在 PVC 释放时删除),StorageClass 为managed-nfs-storage,PVC 状态变为Bound完成绑定。

步骤 4:在 NFS 服务器侧验证数据落盘

测试 Pod 启动完成后会在挂载目录中创建一个SUCCESS文件。到 NFS 服务器共享目录下查看:

. └── default-test-claim-pvc-44d34a50-e00b-4f6c-8005-40f5cc54af18 └── SUCCESS

可以看到:挂载时 nfs-client 根据PVC 所在命名空间 + PVC 名称 + PV UIDdefault-test-claim-pvc-xxxx)自动创建了一个目录,Pod 中挂载的/mnt实际引用的就是该目录,/mnt下创建的SUCCESS文件也自动写入到了这里。

至此,当上层应用需要持久化存储时,只需提供对应的StorageClass即可。很多应用都会根据 StorageClass 来创建它们所需的 PVC,最后再把 PVC 挂载到 Deployment 或 StatefulSet 中使用,例如仓库中集成的 efk、jenkins 等应用。

三、本地存储目录供应者(Local Path Provisioner)

当应用对磁盘 I/O 性能要求较高时,比较适合使用本地文件目录存储,尤其可以本地挂载 SSD 磁盘(注意:本地磁盘需要配置 RAID 冗余策略以保证数据可靠性)。local-path-provisioner(来自 Rancher 社区)可以方便地在 k8s 集群中使用本地文件目录存储,其特点是利用节点本地的空余磁盘目录作为存储后端,无需额外维护网络存储服务,且天然具备接近裸盘的 I/O 性能。

3.1 工作原理与部署清单解读

kubeasz 对应的部署模板为 roles/cluster-addon/templates/local-storage/local-path-storage.yaml.j2,核心内容包括:

  1. RBAC:ServiceAccount、Role/ClusterRole 及绑定,授权 provisioner 管理节点上的 Pod、PVC、PV、StorageClass 与事件;

  2. Deployment:以--config /etc/config/config.json方式启动local-path-provisioner,挂载local-path-configConfigMap 作为配置;

  3. StorageClass

    apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: {{ local_path_storage_class }} # 默认 local-path provisioner: rancher.io/local-path volumeBindingMode: WaitForFirstConsumer # 延迟绑定:等第一个使用它的 Pod 调度完成后才在对应节点创建 PV reclaimPolicy: Delete

    注意volumeBindingMode: WaitForFirstConsumer:local-path 的 PV 依赖具体节点,因此采用"延迟绑定"模式,Pod 被调度到某节点后,provisioner 才在该节点上创建目录并生成 PV,这样 PV 一定落在 Pod 所在节点。

  4. ConfigMaplocal-path-config:其中config.json通过nodePathMap指定节点上的本地存储路径:

    { "nodePathMap": [ { "node": "DEFAULT_PATH_FOR_NON_LISTED_NODES", "paths": ["{{ local_path_provisioner_dir }}"] } ] }

    DEFAULT_PATH_FOR_NON_LISTED_NODES表示对所有未单独列出的节点生效,paths数组中的路径即本地数据落盘目录(默认/opt/local-path-provisioner);ConfigMap 中还内置了setup(创建目录mkdir -m 0777)与teardown(删除目录)脚本,以及helperPod.yaml(在节点上执行卷准备的辅助 Pod 模板,容忍 disk-pressure 污点)。

3.2 在 kubeasz 中启用 Local Path Provisioner

步骤 1:编辑集群配置文件clusters/${集群名}/config.yml

local_path_provisioner_install: "yes" # 修改为 yes # 设置默认本地存储路径 local_path_provisioner_dir: "/opt/local-path-provisioner"

相关参数(默认值见 example/config.yml):

| 参数 | 默认值 | 说明 | | :- | :- | :- | |local_path_provisioner_install|no| 是否安装 local-path provisioner | |local_path_provisioner_ver| 模板变量 | 镜像版本,安装脚本自动填充 | |local_path_storage_class|local-path| 生成的 StorageClass 名称 | |local_path_provisioner_dir|/opt/local-path-provisioner| 节点上的本地存储根目录 |

步骤 2:创建 local path provisioner

$ dk ezctl setup ${集群名} 07

该命令会走与 NFS provisioner 相同的安装流程:由 roles/cluster-addon/tasks/local-storage.yml 渲染local-path-storage.yamltest-pod.yamlclusters/${集群名}/yml/local-storage/并 apply。执行成功后验证:

$ kubectl get pod --all-namespaces | grep provisioner

应能看到local-path-provisioner相关 Pod 处于 Running 状态。

步骤 3:验证使用

kubeasz 在clusters/${集群名}/yml/local-storage/下生成了测试清单test-pod.yaml(模板见 roles/cluster-addon/templates/local-storage/test-pod.yaml.j2),内容为一个 128Mi 的 PVC(storageClassName: local-path、访问模式ReadWriteOnce)和一个挂载该 PVC 到/data的 nginx 测试 Pod:

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: local-path-pvc spec: accessModes: - ReadWriteOnce storageClassName: local-path resources: requests: storage: 128Mi --- apiVersion: v1 kind: Pod metadata: name: volume-test spec: containers: - name: volume-test image: nginx:stable-alpine imagePullPolicy: IfNotPresent volumeMounts: - name: volv mountPath: /data ports: - containerPort: 80 volumes: - name: volv persistentVolumeClaim: claimName: local-path-pvc

应用后可通过kubectl get pvckubectl get pv确认 PVC 绑定,并检查 Pod 所在节点/opt/local-path-provisioner(或自定义目录)下是否生成了对应的卷目录。由于WaitForFirstConsumer的存在,Pod 创建前 PVC 会处于Pending状态,这是预期行为,Pod 调度到节点后 PVC 会自动变为Bound

四、两种存储方案的选型对比

| 维度 | NFS 动态供应(nfs-subdir-external-provisioner) | Local Path 本地供应(local-path-provisioner) | | :- | :- | :- | | 底层存储 | 独立 NFS 服务器共享目录 | 各节点本地磁盘目录 | | 访问模式 | 支持 RWX(多节点读写) | 仅 RWO(单节点读写) | | 适用场景 | 多副本共享读写、日志汇聚(如 EFK)、Jenkins workspace 等 | 高 I/O 性能要求的单副本应用、可本地挂载 SSD | | 数据可靠性 | 依赖 NFS 服务器冗余(如 RAID/备份) | 依赖节点本地磁盘,建议配置 RAID 冗余策略| | 数据位置 | 集中存储于 NFS 服务器 | 分散在各工作节点本地目录 | | 绑定模式 | 立即绑定(Immediate) | 延迟绑定(WaitForFirstConsumer) | | 典型 StorageClass |managed-nfs-storage|local-path|

选型建议:需要多节点共享读写(如日志类、文件类应用)时优先 NFS 动态供应;追求极致磁盘 I/O 且单副本可接受时选择 Local Path 本地存储。

五、总结

本文从 PV/PVC 两个存储抽象入手,完整覆盖了 kubeasz 中两类持久化存储供应者的启用与验证流程:

  1. 静态 PV:适用于 PVC 数量少的场景,通过手写 PV 清单(容量、访问模式、回收策略、StorageClass、NFS 地址路径)与 PVC 完成绑定;
  2. NFS 动态供应:在clusters/${集群名}/config.yml中开启nfs_provisioner_install: "yes"并配置 NFS 服务器信息,执行dk ezctl setup ${集群名} 07一键部署;PVC 提交后 provisioner 自动创建 PV 与 NFS 目录,可在 NFS 服务器侧看到命名空间-PVC名-PV UID目录结构;
  3. Local Path 本地供应:开启local_path_provisioner_install: "yes",通过nodePathMap指定各节点本地目录,采用WaitForFirstConsumer延迟绑定,适合高 I/O 场景。

两种方案对应的配置模板与测试清单都沉淀在仓库的 roles/cluster-addon/templates/nfs-provisioner/ 与 roles/cluster-addon/templates/local-storage/ 目录下,读者可按需阅读模板细节,或结合 docs/guide/nfs-server.md 从零搭建 NFS 服务器后再进行动态供应验证。

【免费下载链接】kubeasz使用Ansible脚本安装K8S集群,介绍组件交互原理,方便直接,不受国内网络环境影响项目地址: https://gitcode.com/GitHub_Trending/ku/kubeasz

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询