1. 为什么K8s需要NFS存储方案
在Kubernetes集群中,持久化存储是运行有状态应用的基础需求。NFS(Network File System)作为经典的网络存储协议,在K8s环境中具有独特优势:
- 跨节点共享访问:多个Pod可以同时挂载同一个NFS目录,适合需要共享存储的场景(如日志收集、媒体处理流水线)
- 协议通用性:几乎所有操作系统都原生支持NFS协议,无需额外驱动
- 成本效益:利用现有NAS设备或简单Linux服务器即可搭建,比商业存储方案成本低80%以上
但原生NFS在K8s中直接使用存在两个核心痛点:
- 需要手动管理PV(PersistentVolume)的创建和回收
- 缺乏动态卷供应能力,无法按需自动创建存储卷
这正是nfs-subdir-external-provisioner的价值所在——它通过StorageClass实现了NFS存储的动态供应。当用户创建PVC(PersistentVolumeClaim)时,provisioner会自动:
- 在NFS服务器上创建子目录(subdir)
- 生成对应的PV资源
- 完成PVC与PV的绑定
2. 环境准备与前置检查
2.1 NFS服务器配置
假设我们已有IP为192.168.1.100的NFS服务器,需确保:
bash复制# 在NFS服务器执行
sudo apt install nfs-kernel-server # Ubuntu/Debian
# 或
sudo yum install nfs-utils # CentOS/RHEL
# 创建共享目录并配置权限
sudo mkdir -p /data/nfs-share
sudo chmod 777 /data/nfs-share
# 编辑exports文件
echo "/data/nfs-share *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
# 应用配置
sudo exportfs -a
sudo systemctl restart nfs-server
关键参数说明:
rw:读写权限sync:同步写入确保数据一致性no_root_squash:允许root用户保持权限(生产环境慎用)no_subtree_check:提升性能但降低安全性
2.2 K8s集群侧验证
在所有Kubernetes节点执行:
bash复制# 安装NFS客户端工具
sudo apt install nfs-common # Ubuntu/Debian
# 或
sudo yum install nfs-utils # CentOS/RHEL
# 测试挂载
mkdir -p /mnt/test
mount -t nfs 192.168.1.100:/data/nfs-share /mnt/test
touch /mnt/test/hello && ls -l /mnt/test
umount /mnt/test
3. Helm安装nfs-subdir-external-provisioner
3.1 添加Helm仓库
bash复制helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update
3.2 定制化values.yaml
创建自定义配置文件nfs-values.yaml:
yaml复制nfs:
server: 192.168.1.100
path: /data/nfs-share
mountOptions:
- nfsvers=4.1 # 建议明确NFS版本避免兼容问题
storageClass:
name: nfs-client
defaultClass: true # 设为默认StorageClass
reclaimPolicy: Delete # PVC删除时自动清理数据
archiveOnDelete: false # 不保留旧数据
3.3 执行Helm安装
bash复制helm upgrade --install nfs-subdir-external-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
-f nfs-values.yaml \
--namespace kube-system \
--create-namespace
验证安装:
bash复制kubectl get pods -n kube-system | grep nfs
kubectl get storageclass
# 应看到nfs-client标记为(default)
4. 实战测试与排错指南
4.1 创建测试PVC
yaml复制# test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
应用并验证:
bash复制kubectl apply -f test-pvc.yaml
kubectl get pvc test-pvc -w # 观察状态变为Bound
# 检查自动创建的PV
kubectl get pv | grep test-pvc
4.2 常见问题排查
问题1:PVC一直处于Pending状态
- 检查项:
bash复制kubectl describe pvc test-pvc # 查看Events kubectl logs -n kube-system -l app=nfs-subdir-external-provisioner - 典型原因:
- NFS服务器防火墙阻塞2049端口
- NFS共享目录权限不足(需777或配置适当的anonuid/anongid)
- 节点未安装nfs-utils包
问题2:Pod挂载超时
- 在Pod描述中通常看到
Timeout waiting for mount错误 - 解决方案:
yaml复制# 在Pod模板中明确NFS版本 volumes: - name: nfs-vol persistentVolumeClaim: claimName: test-pvc mountOptions: - nfsvers=4.1
问题3:删除PVC后数据未清理
- 确认storageClass的reclaimPolicy为Delete
- 手动清理残留数据:
bash复制# 在NFS服务器上查找对应目录 find /data/nfs-share -name "test-pvc-*" -exec rm -rf {} \;
5. 生产环境优化建议
5.1 性能调优参数
在values.yaml中添加:
yaml复制provisioner:
args:
- "--enable-xfs-quota=true" # 启用磁盘配额(需NFS服务器支持XFS)
- "--resync-period=1m" # 资源同步间隔
nfs:
mountOptions:
- nfsvers=4.1
- hard # 持续重试直到服务器恢复
- timeo=600 # 超时时间(0.6秒)
- retrans=5 # 最大重试次数
5.2 高可用方案
-
NFS服务器高可用:
- 使用DRBD+Keepalived构建主备NFS集群
- 或采用云厂商的托管NAS服务(如AWS EFS、阿里云NAS)
-
Provisioner多副本:
yaml复制replicaCount: 2 strategy: type: Recreate # 避免多实例竞争
5.3 安全加固措施
yaml复制securityContext:
fsGroup: 1000 # 限制文件属组
runAsUser: 1000 # 非root用户运行
nfs:
mountOptions:
- sec=sys # 使用AUTH_SYS认证
- proto=tcp # 更可靠的传输协议
6. 进阶使用场景
6.1 多租户隔离方案
通过StorageClass参数实现:
yaml复制apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client-tenant-a
provisioner: cluster.local/nfs-subdir-external-provisioner
parameters:
onParentExist: "keep" # 保留已存在的父目录
pathPattern: "tenant-a/${.PVC.namespace}/${.PVC.name}" # 自定义目录结构
6.2 与Argo Workflows集成
在工作流定义中直接引用:
yaml复制apiVersion: argoproj.io/v1alpha1
kind: Workflow
spec:
volumeClaimTemplates:
- metadata:
name: workdir
spec:
storageClassName: nfs-client
accessModes: [ "ReadWriteMany" ]
resources:
requests:
storage: 5Gi
6.3 监控配置
创建ServiceMonitor监控Provisioner:
yaml复制apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nfs-provisioner-monitor
spec:
endpoints:
- port: metrics
interval: 30s
selector:
matchLabels:
app: nfs-subdir-external-provisioner
我在实际生产环境中发现,当NFS服务器使用机械硬盘时,建议将PVC的IOPS限制设置为:
yaml复制metadata:
annotations:
volume.beta.kubernetes.io/storage-class: |
{
"iopsLimit": "500"
}
