Kubernetes + NFS 动态存储完整踩坑指南(实战)

一、背景与适用场景

在 Kubernetes 集群中,持久化存储是核心能力之一。对于中小规模集群或私有化环境,NFS(Network File System)因其部署简单、成本低、易维护,成为非常常见的存储方案。

尤其在以下场景中非常适用:

  • 数据库(PostgreSQL / MySQL / Redis 持久化)
  • 日志存储(ELK / Loki)
  • 中间件(RabbitMQ / Kafka 部分场景)
  • 开发测试环境

本文基于实战经验(含 PostgreSQL Operator + NFS 动态存储),总结完整部署流程 + 常见踩坑。


二、整体架构

Pod → PVC → StorageClass → NFS Provisioner → NFS Server

组件说明:

  • PVC:用户申请存储
  • StorageClass:定义存储策略
  • NFS Provisioner:动态创建目录
  • NFS Server:真正存储数据

推荐组件:

  • nfs-subdir-external-provisioner(官方维护)

三、NFS 服务端部署

1. 安装 NFS

yum install -y nfs-utils   # CentOS
apt install -y nfs-kernel-server  # Ubuntu

2. 创建共享目录

mkdir -p /data/nfs
chmod -R 777 /data/nfs

3. 配置 exports

vim /etc/exports

/data/nfs *(rw,sync,no_root_squash,no_subtree_check)

4. 启动服务

systemctl enable nfs-server
systemctl start nfs-server
exportfs -rv

四、Kubernetes 客户端准备

所有节点必须安装:

yum install -y nfs-utils

否则会出现典型报错:

mount.nfs: command not found

五、部署 NFS 动态 Provisioner

1. 创建 RBAC

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: run-nfs-client-provisioner
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: nfs-client-provisioner
  namespace: default

2. 部署 Provisioner

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-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.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
        env:
        - name: PROVISIONER_NAME
          value: example.com/nfs
        - name: NFS_SERVER
          value: <NFS_SERVER_IP>
        - name: NFS_PATH
          value: /data/nfs
        volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentvolumes
      volumes:
      - name: nfs-client-root
        nfs:
          server: <NFS_SERVER_IP>
          path: /data/nfs

六、创建 StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
provisioner: example.com/nfs
reclaimPolicy: Retain
volumeBindingMode: Immediate

七、PVC 测试

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs-storage

验证:

kubectl get pvc

八、实战踩坑总结(重点)

1. 权限问题(最常见)

现象:

Permission denied

原因:

  • NFS 默认 root_squash

解决:

no_root_squash
chmod 777

2. Pod 一直 Pending

原因排查顺序:

1)PVC 是否 Bound
2)Provisioner 是否运行
3)StorageClass 是否匹配

关键命令:

kubectl describe pvc
kubectl logs provisioner

3. mount 失败

报错:

mount.nfs: access denied

原因:

  • exports 未放开
  • 防火墙未开

解决:

systemctl stop firewalld

或放行 2049 端口


4. 性能问题(核心坑)

NFS 本质问题:

  • 单点瓶颈
  • 高 IO 延迟

优化建议:

  • SSD 磁盘
  • 独立存储网络
  • 调整 mount 参数
rsize=1048576,wsize=1048576

5. PostgreSQL 场景踩坑(重点)

问题:数据库性能差 / 卡顿

原因:

  • fsync + NFS 延迟

解决建议:

  • 测试环境可用
  • 生产建议:Ceph / 云盘

6. reclaimPolicy 坑

  • Delete:删除 PVC 会删数据
  • Retain:数据保留(推荐)

7. 子目录爆炸问题

现象:

/data/nfs/
  pvc-xxxx
  pvc-yyyy

问题:

  • 文件数量过多
  • inode 耗尽

建议:

  • 定期清理
  • 规范命名

九、最佳实践(强烈建议)

1. 生产环境建议

场景推荐存储
测试NFS
生产数据库Ceph / 云盘
日志NFS / 对象存储

2. 高可用方案

NFS 本身无 HA,建议:

  • Keepalived + VIP
  • 双机热备

3. 安全建议

  • 限制 IP 白名单
  • 不要使用 *

十、总结

NFS 动态存储:

优点:

  • 部署简单
  • 成本低

缺点:

  • 性能瓶颈
  • 无高可用

一句话总结:

👉 “能用,但别在核心生产数据库上用”


十一、进阶建议

如果你已经做到这一步,下一步建议:

  • 学习 Ceph(Rook)
  • 使用 CSI 标准驱动
  • 引入存储监控(Prometheus + Grafana)

(附)排障速查表

问题关键命令
PVC Pendingkubectl describe pvc
挂载失败showmount -e
权限问题chmod 777
Provisioner 异常kubectl logs

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注