NFS服务器的搭建以及在Kubernetes中的使用

本文简要介绍了NFS服务器的搭建以及在Kubernetes中的使用Storage Class进行NFS挂载的操作步骤。

NFS

NFS 是 Network File System 的缩写,是 Sun 公司于1984年开发的一种分布式文件系统协议。它的核心功能就是可以通过网络,让不同的客户端可以彼此访问共同的文件系统,来实现文件的共享。像许多其他的协议,NFS 建立在开放的网络计算的远程过程调用(RPC)之上。NFS 服务器可以让客户端将网络远程的 NFS 服务器分享的目录,直接挂载到本地端的机器当中。本地端的机器通过直接读写挂载的目录,就可以同步到 NFS 服务器之上 [1]

有关 NFS 的更多介绍,可以参看维基百科这篇文章。本文也重度参考了后者。

NFS客户端与服务端通讯过程

NFS的数据传输基于RPC协议,RPC为Remote Procedure Call(远程过程调用)的简写。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求、接受回应进行信息交互的系统。

RPC可以统一管理NFS随机的服务端口,并且统一对外的端口为111。NFS启动之前需要先启动RPC,这样NFS才能够到RPC去注册端口信息。客户端的RPC可以通过向服务端的RPC请求获取服务端的NFS端口信息。当获取到了NFS端口信息后,就会以实际端口进行数据的传输。

客户端与服务端的通讯过程如下[2]

  1. 首先服务器端启动RPC服务,并开启111端口
  2. 服务器端启动NFS服务,并向RPC注册端口信息
  3. 客户端启动RPC(portmap)服务,向服务端的RPC(portmap)服务请求服务端的NFS端口
  4. 服务端的RPC(portmap)服务反馈NFS端口信息给客户端
  5. 客户端通过获取的NFS端口来建立和服务端的NFS连接并进行数据的传输

NFS安装与配置

组件安装

NFS安装需要两个基础组件,分别是RPC主程序rpcbind与NFS主程序nfs-utils

1
2
3
4
5
6
7
8
9
10
11
12
13
# 安装组件
yum install -y rpcbind
yum install -y nfs-utils
# 启动服务
systemctl start rpcbind
systemctl enable rpcbind
systemctl start nfs-server
systemctl enable nfs-server
systemctl start nfs-secure
systemctl enable nfs-secure
# 配置防火墙放行(如已关闭防火墙可不配置)
firewall-cmd --permanent --add-service=nfs
firewall-cmd --reload

服务端配置

  1. 新建文件夹:mkdir /public; chmod 777 /public
  2. 修改/etc/exports并添加/public 192.168.37.0/24(rw,sync)(其中192.168.37.0/24需要改为用户自己机器集群的IP段)
  3. 重载NFS服务:systemctl reload nfs

对于配置文件的详解请看这里。简单来讲,最前面的/public为共享的目录,后面的IP为允许访问客户端的IP网段,其余参数配置在后面的括号中指定,用逗号隔开。rw表示可读写,ro表示只读;sync表示数据写入内存与硬盘,可以保证不丢失,async则优先保存到内存,再保存到硬盘,可以保证高效率,但可能会丢失数据[3]

客户端挂载配置

  1. 使用showmount -e 192.168.37.128查看NFS服务器的共享信息
  2. 在客户端创建目录mkdir /mnt/public
  3. 修改/etc/fstab并添加192.168.37.128:/public /mnt/public nfs defaults 0 0
  4. 使用mount -a使配置生效
  5. 在服务器上使用touch /public/test,可以看到客户端的/mnt/public中也出现了此文件,挂载成功

Kubernetes Storage Class

本小节假设读者已经对Kubernetes有基础的了解。在熟悉Storage Class的概念之前,建议先熟悉VolumePersistent Volume的概念。

持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者使用存储类(Storage Class)来动态供应。PV 持久卷和普通的 Volume 一样,也是使用 Volume 插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。Storage Class为管理员提供了描述存储类的方法,可以实现动态创建 PV。每个 StorageClass 都包含 provisionerparametersreclaimPolicy 字段,这些字段会在 StorageClass 需要动态分配 PersistentVolume 时会使用到。

StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。该字段必须指定。

自动创建的PV会以${namespace}-${pvcName}-${pvName}这样的名字出现在NFS服务器的共享目录中,如果它被回收,则会改为archived-${namespace}-${pvcName}-${pvName}这样的名字[4]

通过Helm安装

安装Helm

安装Helm的方法十分简单,只需遵循官网的安装步骤即可。

Helm Chart 简介

Helm Chart可以理解为 Helm 包,它包含在 Kubernetes 集群内部运行应用程序,工具或服务所需的所有资源定义。你可以把它看作是 Homebrew formula,Apt dpkg,或 Yum RPM 在 Kubernetes 中的等价物。Repository(仓库) 是用来存放和共享 Charts 的地方。Release 是运行在 Kubernetes 集群中的 Chart 的实例,一个 Chart 通常可以在同一个集群中安装多次。每一次安装都会创建一个新的 Release[5]

Helm Chart里通常会有以下部分[6]

  1. Chart.yaml:Chart的元数据信息
  2. values.yaml:定义Chart默认的配置信息
  3. charts/:手动管理的Chart依赖信息
  4. templates/:模板YAML文件,定义所有需要用到的Kubernetes对象

关于更详细的解释,可以参考这篇文章

通过Helm直接安装nfs-subdir-external-provisioner

此部分参考GitHub项目

首先新建一个namespacekubectl create namespace nfs-provisioner,随后执行:

1
2
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner -n nfs-provisioner --set nfs.server=192.168.37.128 --set nfs.path=/public

安装完毕后通过kubectl get all -n nfs-provisioner检查是否正常。

通过第三方镜像安装nfs-subdir-external-provisioner

在网络不好的情况下,在添加Chart Repository后,需要下载并解压修改Chart的配置,使用替换的镜像源。

1
2
3
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm pull nfs-subdir-external-provisioner/nfs-subdir-external-provisioner
tar zxvf nfs-subdir-external-provisioner-4.0.13.tgz

解压完毕,修改文件夹里的values.yaml(下面只列举开头部分):

values.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
replicaCount: 1
strategyType: Recreate

image:
repository: eipwork/nfs-subdir-external-provisioner
tag: v4.0.2
pullPolicy: IfNotPresent
imagePullSecrets: []

nfs:
server: 192.168.37.128
path: /public
mountOptions:
volumeName: nfs-subdir-external-provisioner-root

# ...

随后新建一个namespacekubectl create namespace nfs-provisioner,然后运行helm install nfs-subdir-external-provisioner . -n nfs-provisioner安装nfs-subdir-external-provisioner

安装完毕后通过kubectl get all -n nfs-provisioner检查是否正常。

测试NFS Storage Class

创建test-pvc.yaml

test-pvc.yaml
1
2
3
4
5
6
7
8
9
10
11
12
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
volume.beta.kubernetes.io/storage-class: "nfs-client"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi

检查创建的PV

使用kubectl apply -f test-pvc.yaml创建PVC,随后使用kubectl get pvc查看PVC的信息,可以看到状态为Bound。kubectl get pv也可以看到对应的PV状态也为Bound。

在NFS服务器上使用ls /public查看对应生成的文件夹,名称应该符合${namespace}-${pvcName}-${pvName}这样的规则。再使用kubectl delete -f test-pvc.yaml删除创建的PVC与PV,可以看到对应的文件夹已经改为archived-${namespace}-${pvcName}-${pvName}的名称。

更改默认的Storage Class

默认的Storage Class会在kubectl get sc的结果中以default标记。标记默认的方法:

1
kubectl patch sc <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

取消标记:

1
kubectl patch sc <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

  1. https://cloud.tencent.com/developer/article/1328694 ↩︎

  2. http://zhangguangzhi.top/2017/08/23/14、NFS服务配置/ ↩︎

  3. https://blog.csdn.net/qq_38265137/article/details/83146421 ↩︎

  4. https://www.cnblogs.com/panwenbin-logs/p/12196286.html ↩︎

  5. https://helm.sh/zh/docs/intro/using_helm/ ↩︎

  6. https://helm.sh/zh/docs/chart_template_guide/getting_started/ ↩︎