在 Kubernetes 集群中,持久化存储是有状态应用的重要基础设施。NFS(Network File System)作为一种成熟的网络文件系统,可以为 Kubernetes 提供简单可靠的共享存储解决方案。本文将详细介绍如何部署 NFS StorageClass 实现动态存储供应。
什么是 StorageClass#
StorageClass 是 Kubernetes 中的一种资源对象,用于描述存储的"类别"。它的主要作用包括:
- 动态供应: 自动创建 PersistentVolume(PV)
- 存储抽象: 为不同类型的存储提供统一接口
- 参数化配置: 支持不同的存储参数和策略
- 自动化管理: 减少手动创建 PV 的工作量
方案架构#
本方案采用以下架构:
flowchart LR
Pod[Pod 应用
PVC] -->|动态创建| NFSProvisioner[NFS Provisioner]
NFSProvisioner -->|创建 PV| PV[PV]
PV -->|挂载| NFSServer[NFS Server
NFS Share]
环境准备#
在开始部署之前,请确保您的环境满足以下要求:
| 组件 | 版本/配置 | 说明 |
|---|---|---|
| Kubernetes | v1.19.6+ | 支持 StorageClass 的版本 |
| Helm | v3.4.2+ | 用于部署 NFS Provisioner |
| NFS Server | 任意 Linux 发行版 | 提供 NFS 服务 |
| 网络 | 集群内互通 | 确保 Pod 可以访问 NFS Server |
示例环境配置:
- NFS Server IP: 192.168.8.66
- 网络段: 192.168.8.0/24
- 共享目录: /data/nfs.sharedir
NFS 服务器配置#
第一步:安装 NFS 服务#
在 NFS 服务器上安装必要的软件包:
# 安装 NFS 服务器和相关工具
yum install rpcbind nfs-utils -y
# 启动并设置开机自启
systemctl enable rpcbind nfs-server
systemctl start rpcbind nfs-server
第二步:创建专用用户和目录#
为了安全和管理方便,创建专门的用户来管理 NFS 共享:
# 创建 NFS 用户组
groupadd -g 2233 nfs-user
# 创建 NFS 用户(不创建家目录,不允许登录)
useradd nfs-user -M -s /sbin/nologin -u 2233 -g nfs-user
# 验证用户创建
id nfs-user
# 创建 NFS 共享目录
mkdir -p /data/nfs.sharedir
# 设置目录权限
chown -R nfs-user:nfs-user /data/nfs.sharedir
chmod 755 /data/nfs.sharedir
权限说明:
- 使用固定的 UID/GID (2233) 确保在不同节点上的一致性
- 禁用用户登录提高安全性
- 设置适当的目录权限
服务端 配置文件修改#
cat /etc/exports # 配置文件 如下:
/data/nfs.sharedir 192.168.8.0/24(rw,no_root_squash,no_all_squash,sync,anonuid=2233,anongid=2233)
参数说明:
- read-write,可读写;
- ro:read-only,只读;
- sync:文件同时写入硬盘和内存;
- async:文件暂存于内存,而不是直接写入内存;
- no_root_squash:NFS客户端连接服务端时如果使用的是 root 的话,那么对服务端分享的目录来说,也拥有 root 权限。显然开启这项是不安全的。
- root_squash:NFS客户端连接服务端时如果使用的是 root 的话,那么对服务端分享的目录来说,拥有匿名用户权限,通常他将使用 nobody 或 nfsnobody 身份;
- all_squash:不论NFS客户端连接服务端时使用什么用户,对服务端分享的目录来说都是拥有匿名用户权限;
- anonuid:匿名用户的 UID 值,可以在此处自行设定。
- anongid:匿名用户的 GID 值
执行配置 生效#
exportfs -r
启动服务 & 设置服务开机自启#
service rpcbind start
service nfs start
systemctl enable nfs \
&& systemctl enable rpcbind
nfs 客户端配置#
⚠️ 注意如果在
k8s中使用 nfs时,需要在每一个节点中多配置安装rpcbind,因为 nfs 依赖于使用 rpc 协议进行通讯。yum install rpcbind rpcbind nfs-utils -y service rpcbind start systemctl enable rpcbind
客户端测试挂载#
showmount -e [nfs-server] # 查看服务端 可挂载目录
示例
showmount -e 192.168.8.66
mount -t nfs 192.168.8.66:/data/nfs.sharedir /mnt
如网络不太稳定时,可以尝试切换为
tcp协议mount -t nfs 192.168.8.66:/data/nfs.sharedir /mnt -o proto=tcp -o nolock
部署 nfs storageClass#
helm 添加仓库#
helm repo add stable https://charts.helm.sh/stable
helm repo update
创建 helm 部署文件#
cat > prod-values.yaml << EOF
storageClass:
name: nfs-retain
reclaimPolicy: Retain
nfs:
server: 192.168.8.66
path: '/data/nfs.sharedir'
EOF
reclaimPolicy即PersistentVolumes(pv)的回收策略,包括 “Retain”、“Recycle” 和 “Delete”。 对于动态配置的 PersistentVolumes 来说,默认回收策略为 “Delete”。 这表示当用户删除对应的 PersistentVolumeClaim 时,动态配置的 volume 将被自动删除。 如果 volume 包含重要数据时,这种自动行为可能是不合适的。 那种情况下,更适合使用 “Retain” 策略。 使用 “Retain” 时,如果用户删除 PersistentVolumeClaim,对应的 PersistentVolume 不会被删除。 相反,它将变为 Released 状态,表示所有的数据可以被手动恢复。
部署#
部署至
kube-system命名空间, storageClass 为集群概念,集群内任意命名空间多可以使用。
helm upgrade --install nfs-storage-class -f ./prod-values.yaml -n kube-system stable/nfs-client-provisioner


部署后的测试#
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sc-nginx-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-retain
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sc-nginx
namespace: default
labels:
name: sc-nginx
spec:
replicas: 2
selector:
matchLabels:
name: sc-nginx
template:
metadata:
labels:
name: sc-nginx
spec:
containers:
- name: sc-nginx
image: nginx:1.16.0
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nginx-data
ports:
- containerPort: 80
volumes:
- name: nginx-data
persistentVolumeClaim:
claimName: sc-nginx-pvc
EOF

nfs server 端口 echo 数据 至目录下的 index.html 文件内
echo 'hello' >> /data/nfs.sharedir/default-sc-nginx-pvc-pvc-bd14929c-ed1f-4ede-baa7-a39de13ee169/index.html


