今天来讲讲关于 NFS 的一些知识(主要是我学习的一些笔记,就当现学现卖了!)
当然了,我的水平是有限的,可能会有一些理解错的的概念 or 知识点,还请大家不吝在评论区指正
本篇文章脑图如下:
相关文档:
http://www.tldp.org/HOWTO/NFS-HOWTO/index.html
http://cn.linux.vbird.org/linux_server/0330nfs.php#What_NFS_0
初识NFS
- 什么是NFS?
NFS(Network File System)——网络文件系统
最大的功能就是可以通过网络,让不同的机器不同的操作系统可以共享彼此的文件或目录
所以可以简单的将其看作是一个文件服务器
NFS client 可以将 NFS server 共享的目录挂载到本地的文件系统中,从 client 来看,server 的目录就好像是自己的一个磁盘分区一样
NFS优点
- 节省本地存储空间,将常用的数据放在一台可以通过网络访问的服务器上
- 部署简单快捷,容易上手
- 维护简单
NFS缺点
- 容易发生单点故障,一旦 server 宕机,那么所有 client 都不能访问到
- 高并发情况下容易出现性能瓶颈(server 能力有限)
- NFS 数据是明文传输,而且对数据完整性不做验证,所以安全性较差(一般建议在局域网内使用)
1.RPC远程调度
NFS 支持的功能非常多,且不同的功能都会去使用不同的程序来启动
每启动一个程序就会调用一个端口来进行数据传输,而且 NFS 功能调用的端口并不固定,是随机的
既然是随机端口,NFS client 又是如何知道 NFS server 到底是使用哪个端口进行文件共享的呢?
这时候就需要通过远程过程调用(Remote Procedure Call, RPC)协议来实现了!
- 什么是RPC协议?
RPC(Remote Procedure Call)即远程过程调用。
RPC统一对外端口是111,主要的功能就是记录每个 NFS 功能所对应的端口 ,并且通知给客户端,让客户端可以连接到正确的端口上去
- 那么RPC又是如何知道每个 NFS 功能的端口呢?
当 NFS 服务启动时会启用一些随机的端口,然后 NFS 就会向 RPC 去注册这些端口,RPC 就记录下这些端口
且 RPC 开启111端口去等待客户端请求,如果客户端有请求,那么 RPC 就会这些之前记录的 NFS 端口信息通知给客户端
此客户端就会获取 NFS 服务器端的端口信息,就会以实际端口进行数据的传输了
PS:
在启动 NFS server 之前首先要启动 RPC 服务(portmap 服务)否则 NFS server 就无法向 RPC 服务去注册
如果 RPC 服务重启,原来已经注册好的 NFS 端口数据会全部丢失,因此 NFS 服务也要重启以便重新向 RPC 注册
一般修改 NFS 配置文档后,是不需要重启 NFS 的,直接执行 exportfs -r -v 即可
- NFS 启动的 RPC daemons
我们现在知道 NFS 服务器在启动的时候就得要向 RPC 注册,所以 NFS 服务器也被称为 RPC server 之一。 那么 NFS 服务器主要的任务是进行文件系统的分享,文件系统的分享则与权限有关。 所以 NFS 服务器启动时至少需要两个 daemons ,一个管理客户端是否能够登入的问题, 一个管理客户端能够取得的权限
rpc.nfsd:
最主要的 NFS 服务器服务提供者,主要功能就是管理客户端是否能够使用服务器文件系统挂载信息
rpc.mountd
负责管理 NFS 的文件系统,当客户端通过 rpc.nfsd 登录到服务器后,在它可以使用 NFS server 的共享目录之前,还会经过共享目录的权限的认证
该进程会去读取 NFS 的配置文件( /etc/exports )来对比客户端的权限
rpc.lockd (非必要)
负责给共享目录加锁,当多个客户端同时尝试写入某个共享文件时,就会出现问题
rpc.lockd 可以解决这个问题,但 rpc.lockd 必须要同时在客户端与服务器端都开启才行。此外, rpc.lockd 也常与 rpc.statd 同时启用
rpc.statd (非必要)
负责检查共享文件的一致性,与 rpc.lockd 有关
若发生因为客户端同时使用同一档案造成档案可能有所损毁时, rpc.statd 可以用来检测并尝试回复该档案。与 rpc.lockd 同样的,这个功能必须要在服务器端与客户端都启动才会生效
2.NFS 工作过程
- 首先服务器端启动 RPC 服务,并开启 111 端口
- 服务器端启动 NFS 服务,并向 RPC 注册端口信息
- 客户端启动RPC(portmap服务),向服务端的 RPC (portmap) 服务请求服务端的NFS端口
- 服务端的 RPC(portmap) 服务返回 NFS 端口信息给客户端。
- 客户端通过获取的 NFS 端口来建立和服务端的 NFS 连接并进行数据的传输
3.NFS 权限
不知道你有没有想过这个问题,假如 client 以 user1 这个身份去对 NFS server 提供的共享目录进行操作时,NFS server 提供的共享目录会让 client 以什么身份去操作,user1还是其他?
这是因为 NFS 服务是没有身份识别的,所以说当 client 以 user1 的身份对共享目录进行操作时, server 会以 client 当前用户(即 user1)的 UID 和 GID 等身份来尝试操作 server 的共享目录(即系统不识别用户名字,只识别用户对应的 UID 和 GID)
这时就会有一个问题产生:如果 client 与 server 的使用者身份并不一致怎么办?
当 client 以 user1 这个一般身份去操作来自 server 的共享目录时,首先要注意到的是——文件系统的 innode 所记录的属性为 UID、GID 而非账号名和群组命
一般 Linux 系统会主动的以自己的 /etc/passwd, /etc/group 来查询对应的账号名、组名。
所以当 user1 首先会参照 client 的账号名和组名(假设 user1 的 UID 是666),但是由于该共享目录来自 server端,所以就可能会发生以下情况:
NFS server/NFS client 刚好有相同的账号与群组(即 server 端 UID 为 666 的用户为 user1)
- 此时 client 可以直接以 user1 的身份对共享目录进行操作
NFS server 的 666 这个 UID 账号对应为 test
-
- 如果 NFS server 上 UID 为 666 的用户为 test 时,则 client 的 user1 用户可以直接操作 test 用户的共享目录
- 因为这两个用户具有相同的 UID
- 这就造成很大的问题了!因为没有人可以保证 client 的 UID 所对应的账号会与 server 相同, 那 server 所提供的数据不就可能会被错误的用户乱改
NFS server 没有 666 这个 UID
- 在 server 端并没有666这个 UID,那么 user1在该共享目录下会被压缩成匿名用户
- 一般 NFS 的匿名用户会以 UID 为 65534 为其使用者
- 但有时也会有特殊的情况,例如在服务器端分享 /tmp 的情况下, user1 的身份还是会保持 666 但创建的数据在服务端来看,就会属于 nobody
root 用户
- 想一想,如果 client 用 root 的身份去操作服务器端的文件系统时,那 server 的数据还有什么保护性? 所以在预设的情况下, root 的身份会被主动的压缩成为匿名者
总的来讲,client 的权限是与 UID 和 GID 相关的,当 client 与 server 的 UID 对应的用户不一致时,就有可能造成一些问题
NFS配置权限设置,即/etc/exports文件配置格式中小括号()里的参数集
参数 | 说明 |
---|---|
ro | 只读访问 |
rw | 读写访问 |
sync | 同步传输数据,读写数据时,数据同步到 NFS server硬盘后才返回 |
async | 异步传输数据,写入数据时会先写到内存缓存区 |
secure | nfs 通过 1024 以下的安全 TCP/IP 端口发送 |
insecure | nfs 通过 1024 以上的端口发送 |
wdelay | 如果多个用户要写入 nfs 目录,则归组写入(默认) |
no_wdelay | 如果多个用户要写入 nfs 目录,则立即写入,当使用 async 时,无需此设置 |
hide | 在 nfs 共享目录中不共享其子目录 |
no_hide | 共享 nfs 目录的子目录 |
subtree_check | 如果共享 /usr/bin 之类的子目录时,强制 nfs 检查父目录的权限(默认) |
no_subtree_check | 不检查父目录权限 |
all_squash | 共享文件的 UID 和 GID 映射匿名用户 anonymous,适合公用目录 |
no_all_squash | 保留共享文件的 UID 和 GID(默认) |
root_squash | root 用户的所有请求映射成如 anonymous 用户一样的权限(默认) |
no_root_squash | root 用户具有根目录的完全管理访问权限 |
anonuid=xxx | 指定 nfs 服务器 /etc/passwd 文件中匿名用户的 UID |
anongid=xxx | 指定 nfs 服务器 /etc/passwd 文件中匿名用户的 GID |
4.NFS 相关文件
主要配置文件:/etc/exports
NFS的配置文件,可能必须要使用 vim 主动的建立起这个文件
NFS 文件系统维护指令:/usr/sbin/exportfs
维护 NFS 共享资源的命令,可以对共享资源进行更新、卸载等
共享资源的登录文件:/var/lib/nfs/*tab
在 NFS server的登录文件都放置到 /var/lib/nfs/ 目录里面,在该目录下有两个比较重要的登录文件
一个是 etab ,主要记录了 NFS 所共享出来的目录的完整权限设定值;
另一个 xtab 则记录曾经连接到此 NFS 服务器的相关客户端数据
客户端查询服务器分享资源的指令:/usr/sbin/showmount
showmount 则主要用在 Client 端, 可以用来查看 NFS server 共享出来的目录资源
NFS 案例
有两台 web 服务器通过 NFS 将后端存储服务器的数据挂载到本地
用户去访问 web 服务器上的资源,其实访问的是后端存储服务器的资源
架构图如下:
- web1:192.168.149.130
- web2:192.168.149.131
- NFS server:192.168.149.129
1.NFS server
安装 NFS、RPC 服务
[root@server ~]# yum install -y nfs-utils rpcbind
创建共享目录作为客户端挂载的远端入口
[root@server ~]# mkdir /data/{web1,web2} -pv
修改 NFS 配置文件
[root@server ~]# vim /etc/exports
/data/web1 192.168.149.130(rw,sync,insecure,no_subtree_check,no_root_squash)
/data/web2 192.168.149.131(rw,sync,insecure,no_subtree_check,no_root_squash)
一般修改 NFS 配置文档后,是不需要重启 NFS 的,直接执行 exportfs -r -v 即可
启动 rpc 服务
[root@server ~]# systemctl start rpcbind.service
注意:此时我们还没有启动 NFS 服务,只监听了 111 端口,接着我们来启动 NFS 服务
[root@server ~]# systemctl start nfs.service
启动了 NFS 服务后,rpc 注册的端口列表明显增多。现在服务端都启动起来了,在服务端看下是否正确加载了设置的 /etc/exports
配置
[root@server ~]# showmount -e localhost
Export list for localhost:
/data/web2 192.168.149.131
/data/web1 192.168.149.130
接着我们在共享目录下存放web资源
[root@server ~]# cat /data/web1/test.html
<h1> I am NFS server</h1>
<h2> This is web1 </h2>
[root@server ~]# cat /data/web2/test.html
<h1> I am NFS server</h1>
<h2> This is web2 </h2>
2.NFS client
安装nginx提供web服务
yum install epel-release -y
yum install -y nginx
安装 nfs 服务
yum install -y nfs-utils
nginx配置
#web1
vim /etc/nginx/conf.d/web.conf
server{
listen 8080;
root /mnt/html/;
index test.html;
}
#web2
vim /etc/nginx/conf.d/web.conf
server{
listen 8080;
root /mnt/html/;
index test.html;
}
web1、web2 分别创建挂载目录
mkdir /mnt/html/
我们可以在客户端查看下 NFS server ( IP 为:192.168.149.129 ) 设置可共享的目录信息
[root@web1 ~]# showmount -e 192.168.149.129
Export list for 192.168.149.129:
/data/web2 192.168.149.131
/data/web1 192.168.149.130
[root@web2 ~]# showmount -e 192.168.149.129
Export list for 192.168.149.129:
/data/web2 192.168.149.131
/data/web1 192.168.149.130
web1挂载 NFS server 的 /data/web1 共享目录
[root@web1 ~]# mount -t nfs 192.168.149.129:/data/web1 /mnt/html
[root@web1 ~]# df -Th
文件系统 类型 容量 已用 可用 已用% 挂载点
192.168.149.129:/data/web1 nfs4 17G 2.1G 15G 12% /mnt/html
web2挂载 NFS server 的 /data/web2 共享目录
[root@web2 ~]# mount -t nfs 192.168.149.129:/data/web2 /mnt/html
[root@web2 ~]# df -Th
文件系统 类型 容量 已用 可用 已用% 挂载点
192.168.149.129:/data/web2 nfs4 17G 2.1G 15G 12% /mnt/html
3.验证
我们分别访问web1、web2,看下是否能够正确读取并修改
[root@server ~]# curl 192.168.149.131:8080
<h1> I am NFS server</h1>
<h2> This is web2 </h2>
[root@server ~]# curl 192.168.149.130:8080
<h1> I am NFS server</h1>
<h2> This is web1 </h2>
[root@web1 ~]# echo "hello" >> /mnt/html/test.html
#在 NFS server 上查看,可以看到成功修改了
[root@server ~]# cat /data/web1/test.html
<h1> I am NFS server</h1>
<h2> This is web1 </h2>
hello
最后,如果客户端要卸载 NFS 挂载的话,使用如下命令即可
umount /mnt/html
[鸟哥的 Linux 私房菜 -- NFS 服务器 (vbird.org)](