容器持久化方案:NFS实现
NFS 是一种非常经典的网络共享存储协议,它允许一台计算机通过网络访问另一台计算机的磁盘,就像访问本地磁盘一样。在容器生态中,NFS 是实现共享存储持久化的常用且成熟的选择。
一、为什么需要持久化?为什么选择 NFS?
- 容器的本质问题:容器默认的文件系统是分层和临时性的。当容器被删除或重启后,其内部产生的数据(如日志、上传的文件、数据库数据)也会随之消失。
- 持久化的目标:将容器内应用程序的重要数据存储在容器生命周期之外的地方,确保数据安全且可独立管理。
- NFS 的优势
- 共享访问:多个 Pod(容器)可以同时以读写模式挂载同一个 NFS 目录,非常适合需要共享数据的分布式应用(如负载均衡后的多个 Web 服务器共享上传目录)。
- 独立于节点:数据存储在集中的 NFS 服务器上,与运行容器的宿主机节点解耦。即使节点宕机,Pod 被调度到其他节点,依然可以挂载并访问原来的数据。
- 成熟稳定:NFS 是经过几十年考验的协议,Linux 内核原生支持,非常稳定。
- 成本较低:可以利用现有的 NAS 存储设备或简单搭建一台 NFS 服务器,无需复杂的分布式存储系统。
二、整体架构
在一个典型的 Kubernetes 集群中使用 NFS 持久化的架构如下:
text
+-------------------------------------------------------+
| Kubernetes Cluster |
||
|+------------+ +------------+ +------------+|
|| Pod A | | Pod B | | Pod C ||
| | (Node 1) | | (Node 2) | | (Node 3) ||
|+------------+ +------------+ +------------+|
|| Volume | | Volume | | Volume ||
| | Mountpoint | | Mountpoint | | Mountpoint ||
|+------+-----+ +------+-----+ +------+-----+|
|| | | |
+---------|-------------------|-------------------|------+
| | |
| (NFS Protocol over Network) |
| |
+---------+---------------------------------------+-----+
| External to Cluster |
||
|+---------------------+ |
|| NFS Server | |
|| | |
|| /exported/data/path <---------+ |
|+---------------------+ | |
|| |
| Physical Disk/NAS |
+-------------------------------------------------------+
- NFS Server:独立的服务器(物理机、虚拟机或云上的 NAS 服务),导出(export)一个或多个目录。
- Kubernetes Nodes:所有工作节点都需要安装 nfs-common 包(包含 mount.nfs 命令),以便能够挂载 NFS 共享。
- Pod:通过 Volume 配置,将远端的 NFS 目录挂载到容器内的指定路径。
三、操作步骤(以 Kubernetes 为例)
步骤 1:准备 NFS 服务器
假设 NFS 服务器 IP 为 192.168.1.100,要共享的目录是 /data/k8s_nfs。
- 安装 NFS 服务端 (
在 NFS Server 上执行):
bash
# Ubuntu/Debian
sudo apt-get update && sudo apt-get install -y nfs-kernel-server
# CentOS/RHEL
sudo yum install -y nfs-utils
- 创建共享目录并设置权限:
bash
sudo mkdir -p /data/k8s_nfs
sudo chown nobody:nogroup /data/k8s_nfs # 根据情况修改所有权,或使用 anonuid/anongid
sudo chmod 777 /data/k8s_nfs # 为简单测试,可先放宽权限
- 配置导出目录:
编辑 /etc/exports 文件,添加以下行:
text
/data/k8s_nfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
-
- /data/k8s_nfs:要共享的目录。
- 192.168.1.0/24:允许访问的客户端网段(请根据你的集群网络修改)。
- rw:读写权限。
- sync:同步写入,更安全。
- no_subtree_check:提高性能。
- no_root_squash:允许客户端上的 root 用户保持 root 权限(慎用,有安全风险。生产环境建议使用 all_squash 并映射到特定用户)。
- 使配置生效:
bash
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
sudo systemctl enable nfs-kernel-server
步骤 2:配置Kubernetes 节点
在所有 Kubernetes Worker 节点上安装 NFS 客户端软件。
bash
# Ubuntu/Debian
sudo apt-get update && sudo apt-get install -y nfs-common
# CentOS/RHEL
sudo yum install -y nfs-utils
步骤 3:在Kubernetes 中创建 PV 和 PVC
Kubernetes 推荐使用 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 来管理存储。
- 创建 PersistentVolume (PV):
PV 是集群中的一块存储,由管理员预先制备。它是对底层存储(如 NFS 共享)的抽象。
nfs-pv.yaml
yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 10Gi # 存储容量(NFS本身无限制,这里起声明作用)
volumeMode: Filesystem
accessModes:
- ReadWriteMany # NFS 支持多节点读写,这是其关键优势
persistentVolumeReclaimPolicy: Retain # 删除PVC后,PV保留(数据手动清理)
storageClassName: nfs
nfs:
path: /data/k8s_nfs # NFS服务器上的路径
server: 192.168.1.100 # NFS服务器IP
应用配置:kubectl apply -f nfs-pv.yaml
- 创建 PersistentVolumeClaim (PVC):
PVC 是用户对存储的请求。Pod 通过 PVC 来使用 PV。
nfs-pvc.yaml
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
storageClassName: nfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi # 请求的存储大小,必须小于等于PV的容量
# volumeName: nfs-pv # 可选的,可以指定绑定到特定的PV
应用配置:kubectl apply -f nfs-pvc.yaml
使用 kubectl get pv,pvc 查看状态,应显示 Bound。
步骤 4:在 Pod 中引用 PVC
在 Pod 的定义中,使用 persistentVolumeClaim 卷类型来挂载存储。
pod-example.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nfs-storage
mountPath: /usr/share/nginx/html #容器内的挂载路径
volumes:
- name: nfs-storage
persistentVolumeClaim:
claimName: nfs-pvc # 引用之前创建的PVC
应用配置:kubectl apply -f pod-example.yaml
现在,容器内 /usr/share/nginx/html 目录下的任何读写操作,实际上都会发生在 NFS 服务器的 /data/k8s_nfs 目录下。
四、动态 Provisioning(可选)
上述方式是静态制备,需要管理员手动创建 PV。更高级的方式是动态制备,即无需手动创建 PV,当用户创建 PVC 时,自动创建对应的 PV。
这需要部署一个 NFS Subdir External Provisioner(例如 nfs-subdir-external-provisioner Helm Chart)。这个 Provisioner 会监视 PVC 的创建,并自动在指定的 NFS 共享目录下创建以命名空间和 PVC 名称命名的子目录作为新的 PV,极大简化了管理流程。
五、常见问题与注意事项
- 性能:NFS 的性能受网络带宽和延迟影响较大,不适合对 I/O 延迟要求极高的应用(如高性能数据库)。考虑使用 SSD 和万兆网络来提升性能。
- 安全性:
-
在生产环境中,避免使用 no_root_squash。
-
考虑使用 Kerberos 等认证方式增强 NFS 安全性。
-
网络隔离,确保 NFS 流量只在 trusted network 中传输。
-
- 单点故障:NFS 服务器本身是一个单点。解决方案是使用高可用的 NAS 设备,或者使用 DRBD 等技术构建高可用 NFS 集群。
- 权限问题:容器内进程的用户 UID 必须对 NFS 共享目录有相应的读写权限。这通常需要在运行容器时指定 securityContext.runAsUser 或确保 NFS 服务器端正确配置了 squash 和 UID/GID 映射。
总结
NFS 为容器持久化提供了一个简单、有效且支持多节点共享的解决方案。它非常适合存储应用程序日志、用户上传的内容、配置文件等需要跨容器实例共享或持久化的数据。虽然它在性能和单点故障方面存在一些挑战,但对于大多数中小型应用和非极端性能要求的场景,NFS 仍然是一个极具性价比和实用性的选择。
更多推荐


所有评论(0)