原生 NFS + NFS Subdir External Provisioner,这是 K8S 社区最主流的方案 ——原生 NFS 服务器提供存储能力,NFS Subdir Provisioner 实现 K8S 动态 PV 供应,能自动为每个 PVC 创建专属 NFS 子目录(避免多 PVC 数据混叠),部署简单、维护成本低,适合 90% 的中小规模 K8S 集群,部署以Ubuntu24为例。
搭建K8S后端存储的NFS服务器流程
首先了解当前服务器的存储情况和环境配置。
第一步:检查存储设备情况
- 查看磁盘列表:
lsblk
识别到新设备(如
/dev/sdb),未分区、未格式化。
- 确认磁盘详情:
sudo fdisk -l /dev/sdb
确认
/dev/sdb是未分区的新磁盘。
第二步:准备数据盘
(步骤:创建分区 → 格式化文件系统 → 创建挂载点并挂载)
- 创建磁盘分区:
echo -e "n\np\n1\n\n\nw" | sudo fdisk /dev/sdb
- 格式化文件系统(ext4):
sudo mkfs.ext4 /dev/sdb1
- 创建挂载点:
sudo mkdir /nfs-storage
- 挂载分区到挂载点:
sudo mount /dev/sdb1 /nfs-storage
- 配置开机自动挂载:
sudo tee -a /etc/fstab <<EOF
/dev/sdb1 /nfs-storage ext4 defaults 0 0
EOF
- 验证挂载情况:
df -h /nfs-storage
显示
/dev/sdb1已挂载到/nfs-storage即成功。
第三步:安装NFS服务器
sudo apt update && sudo apt install -y nfs-kernel-server
第四步:配置NFS共享
- 创建NFS共享目录结构:
sudo mkdir -p /nfs-storage/k8s-pvs
- 修改共享目录权限:
sudo chown nobody:nogroup /nfs-storage/k8s-pvs && sudo chmod 777 /nfs-storage/k8s-pvs
- 配置
/etc/exports(NFS共享规则): (注:原直接编辑文件失败,改用tee命令)
sudo tee /etc/exports <<'EOF'
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
/nfs-storage/k8s-pvs *(rw,sync,no_subtree_check,no_root_squash,fsid=0)
EOF
第五步:启动和配置NFS服务
- 重启NFS服务:
sudo systemctl restart nfs-kernel-server
- 设置NFS服务开机自启:
sudo systemctl enable nfs-kernel-server
- 验证NFS共享配置:
sudo exportfs -v
第六步:配置防火墙(如果需要)
- 检查防火墙状态:
sudo ufw status
若防火墙未启用,则无需额外配置。
第七步:测试NFS共享
- 本地创建测试挂载点并挂载NFS:
sudo mkdir -p /tmp/test-nfs && sudo mount -t nfs localhost:/nfs-storage/k8s-pvs /tmp/test-nfs
- 写入测试文件验证:
df -h /tmp/test-nfs && echo "NFS测试成功" | sudo tee /tmp/test-nfs/test.txt
- 卸载测试挂载点并清理:
sudo umount /tmp/test-nfs && sudo rmdir /tmp/test-nfs
第八步:创建NFS Subdir Provisioner所需目录
sudo mkdir -p /nfs-storage/k8s-pvs/.nfs-provisioner && sudo chown nobody:nogroup /nfs-storage/k8s-pvs/.nfs-provisioner
第九步:验证最终配置
(示例:检查共享目录权限)
ls -ld /nfs-storage/k8s-pvs
第十步:生成K8S部署配置文件(nfs-provisioner-deployment.yaml)
# NFS Subdir External Provisioner Deployment for K8S
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
namespace: default
---
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: ["events"]
verbs: ["create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: leader-locking-nfs-client-provisioner
namespace: default
rules:
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: leader-locking-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-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: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.9.2 # 替换为你的NFS服务器IP
- name: NFS_PATH
value: /nfs-storage/k8s-pvs
volumes:
- name: nfs-client-root
nfs:
server: 192.168.9.2 # 替换为你的NFS服务器IP
path: /nfs-storage/k8s-pvs
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "true"
reclaimPolicy: Delete
allowVolumeExpansion: true
完成总结
已完成的核心配置
-
存储准备:
- 识别并分区格式化新磁盘(
/dev/sdb) - 格式化为
ext4文件系统 - 创建
/nfs-storage挂载目录 - 配置开机自动挂载
- 识别并分区格式化新磁盘(
-
NFS服务器:
- 安装
nfs-kernel-server服务 - 创建NFS共享目录(
/nfs-storage/k8s-pvs) - 配置
/etc/exports允许所有客户端访问(权限:rw,sync,no_subtree_check,no_root_squash,fsid=0) - 启动并设置NFS服务开机自启
- 本地挂载测试验证
- 安装
NFS服务器信息
- 服务器IP:
192.168.9.2 - 共享路径:
/nfs-storage/k8s-pvs - 访问权限:所有客户端可读写
K8S部署准备
-
已生成
nfs-provisioner-deployment.yaml文件,包含:- ServiceAccount和RBAC权限配置
- NFS Provisioner Deployment
- NFS StorageClass
下一步操作
- 在K8S集群中部署Provisioner:
kubectl apply -f nfs-provisioner-deployment.yaml
- 创建测试PVC验证:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-nfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: nfs-storage
PVC创建后会自动绑定PV,PV实际路径对应
/nfs-storage/k8s-pvs/default-test-nfs-pvc-xxx
安全建议(可选)
- 限制NFS访问来源为K8S节点网段(替换
/etc/exports中的*) - 启用NFS的Kerberos认证
- 定期备份NFS存储数据