NFS,全称Network File System(网络文件系统),位于TCP/IP的传输层之上,实现linux/unix平台之间的文件共享。
一、NFS部署
学以致用,但要先会用,而且毕竟本是偏向于运维的知识范畴,还是从怎么部署NFS讲起吧!
NFS是CS架构的协议,需要启动一个NFS Server,配置共享目录和权限,NFS Client就可以挂载共享目录到本地目录上,直接打开本地目录进行读写。
在不同操作系统上安装NFS
1.Ubuntu/Linux
- 安装NFS软件包
sudo apt-get install nfs-kernel-server # 安装 NFS服务器端
sudo apt-get install nfs-common # 安装 NFS客户端
- 配置 NFS 共享目录
sudo vim /etc/exports
配置示例:
/nfsroot *(rw,sync,no_root_squash) # * 表示允许任何网段 IP 的系统访问该 NFS 目录
创建’nfsroot’目录并赋予权限
sudo mkdir /nfsroot
sudo chmod -R 777 /nfsroot
sudo chown ipual:ipual /nfsroot/ -R # ipual 为当前用户,-R 表示递归更改该目录下所有文件
- 启动NFS服务
sudo /etc/init.d/nfs-kernel-server start
# 或者
sudo /etc/init.d/nfs-kernel-server restart
- 挂载NFS服务器
在NFS Client端执行
sudo mount -t nfs 10.11.97.234:/nfsroot /mnt -o nolock
10.11.97.234 为主机 ip,/nfsroot 为主机共享目录,/mnt 为设备挂载目录。
另外,也可以先本地挂载验证下,IP使用127.0.0.1。
如需卸载:
umount /mnt
注意点:
- NFS Client和Server直接的网络要通畅
- 更改了/etc/exports之后需要重启
2. Win10
- 安装haneWIN NFS Server
- 配置共享目录(Windows的操作就是都比较可视化)
- 安装NFS Client
- 使用cmd,挂载
mount 10.11.97.234:/g/nfsroot x:
注意点:
- Windows作为Client,只能挂载到一个 未使用 的盘符上,而不是具体目录
- 挂载的共享目录路径,需要是Exports(输出)界面下的路径,如/nfsroot,而不能是Windows盘符的路径
3.Mac OS
- Mac默认安装了 NFS Server,检查nfsd的启动情况
sudo nfsd status
如果没有开启,执行以下指令启动
sudo nfsd enable
sudo nfsd start
- 配置共享目录
sudo vi /etc/exports
配置方式基本和linux差不多
/Users/mac/nfs-share -alldirs -maproot=root:wheel -network=192.168.0.0 -mask=255.255.0.0
3. 启动服务
# 检查配置状态
sudo nfsd checkexports
# 重启服务
sudo nfsd restart
# 查看挂载状态
showmount -e
- 挂载
sudo mount -t nfs -o nolock,nfsvers=3,vers=3 192.168.31.103:/Users/mac/nfs-share /Users/mac/demo
以上给了我们平时经常会用的OS的配置方式,主流其实还是以CenterOS为代表的Linux,因为NFS一般是为了实现文件服务器集群的。
/etc/exports的配置格式
共享目录路径 允许的IP或主机名1(选项1,选项2,...) 允许的IP或主机名2(选项1,选项2,...)
mount格式
mount.nfs <服务器 IP 或主机名>:<共享路径> <挂载点> [-o <选项>]
【查看NFS状态】
ps -aux|grep -v grep|grep nfs
rpcinfo -p
【查看udp和tcp的端口占用】
netstat -tunlp
Android
- Android要在kernel层开启NFS,可以在kernel目录下执行 make menuconfig ,找到对应选项勾选,重新编译kernel。
- 重新烧录resources.img,kernel.img,即可执行 busybox mount -t nfs -o nolock,rw 10.11.97.234:/home/szc/nfsroot /mnt/sdcard/nfs
BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件
内核的配置文件也可开启:
路径:kernel-5.10/arch/arm64/configs/rockchip_defconfig
配置:
# NFS支持
CONFIG_NFS_FS=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NFS_SWAP=y
二、协议剖析
先来看一张NFS的CS架构图:
由此可见,NFS的基础是RPC,那么什么是RPC呢?作为一个客户端出身的嵌入式开发,自然不是很了解,但对于后台服务器开发,这却是构建分布式的基石,包括如今非常流行的微服务。
RPC(Remote Procedure Call)远程过程调用协议,那过程是什么?过程就是业务处理、计算任务。说简单点,就像调用一个本地方法,调用远程计算机上的方法,对调用方来说屏蔽了网络传输相关的实现。
RPC执行过程是什么样的?
所以RPC的实现主要涉及动态代理和序列化,这也是开发者首先接触到的两块内容。
首先讲述一下远程方法是怎么调用的,其实就是协议的设计:
- 假如RPC Server有一个com.hikvision.Test.java,定义了String hello(String hello) { xxx } 方法,我们需要怎么调用他?
答:包名+类名+方法名+方法签名(避免重载)+方法参数,即可明确一个方法。 - 那么动态代理的作用是什么?
答:解耦,运行时生成代理类,实现“偷梁换柱”,屏蔽远程调用的细节 - 网络传输需要序列化,xml、json都是序列化,选择序列化框架也尤其重要,需要同时考虑性能和兼容性等,如Hessian、Protobuf。
NFS通信过程
了解完RPC是什么,再回过头看看NFS服务器和客户端的通信过程:
- 首先,客户端的RPC程序连接到服务器上的111端口(UDP)来查询NFS各项服务所使用的端口
- 分别连接rpc.nfsd和rpc.mountd端口,获取挂载点的信息
- 挂载文件系统,客户端即可操作共享文件系统了
搬运一张Wireshark的抓包图,辅助理解:
三、NFS服务的权限和用户映射
NFS服务虽然不具备用户身份验证的功能,但提供了一种身份映射的机制来对用户身份进行管理。
nfsnobody:NFS服务在系统中自动创建的程序用户账号,不能用于登录系统,专门用作NFS服务的匿名用户账号。
压缩配置在/etc/exports,有如下选项:
root_squash | 默认值,当NFS客户端以root用户身份访问时,映射为NFS服务器的nfsnobody用户。 |
no_root_squash | 当NFS客户端以root身份访问时,映射为NFS服务器的root用户,也就是要为超级用户保留权限。这个选项会留下严重的安全隐患,一般不建议采用。 |
all_squash | 无论NFS客户端以哪种用户身份访问,均映射为NFS服务器的nfsnobody用户。 |
具体流程如下图所示:
这边的压缩,其实有点映射的意思。
所以,在实际应用中,一般NFS服务器当存储服务,为了方便各个用户
能像操作本地磁盘一样存取,一般采用将用户压缩成指定用户的方式,并且在NFS服务器上将共享目录的权限配置为该用户和所属组。
四、NFS相关服务
名称 | 用途 |
rpc.nfsd | 必要,NFS的主要服务进程,大部分工作由它来完成,主要负责登录和判别登录者ID |
rpc.mountd | 必要,主要共享目录的文件权限判断,读取/etc/exports |
rpc.lockd | 非必要,管理文件的锁定,解决多个客户端同时写入某个文件的问题,必须同时在客户端与服务端都开启才有效,常与rpc.statd同时使用 |
rpc.statd | 非必要,用于检查文件的一致性,检测文件是否被损毁,必须同时在客户端与服务端都开启才有效 |
rpcbind: rpcbind的功能与DNS服务器非常相似,DNS根据域名查找IP,rpcbind是查找功能对应的port,所以,早期的rpcbind叫portmap。基本原理如下所示:
通过IP和port就可以建立起具体功能的连接了,回想一下,http、redis等等都是这么建立连接的。
至此,NFS的CS之间怎么建立起通信就分析完了,通过NFS模糊了设备间的边界,到了文件系统这一步,VFS和fuse,以及内部DMA及VMA管理,需要另开篇幅分析linux操作系统,此处不再赘述。
另外来看看NFS相关的代码结构,加深一下印象。
kernel内核的nfs:
在fs目录,说明定位是文件系统,同目录还有熟悉的fuse、quota,下回分解。libnfs的源码,也可以看nfsutils的源码,都是nfs的应用