简介
NFS 服务是除 Samba、FTP 之外的另外一个文件共享方式,它是 Network File System 的缩写,中文称 「网络文件系统」
如同 Samba 客户端一样,NFS 可以让客户端把服务器的共享目录 挂载 到本机使用,就像使用本机分区一样,直接在线修改、上传、下载等。
NFS 主要在 GNU/Linux 服务器和 GNU/Linux 客户端之间使用,采用的是 C/S 架构。NFS 的配置比较简单,所以当客户端和服务器端都是 GNU/Linux 的时候,愿意使用 NFS 作为基本的文件共享方式。
服务名称 | 使用范围 | 服务器端 | 客户端 | 局限性 |
---|---|---|---|---|
FTP | 局域网与公网 | Windows、GNU/Linux | Windows、GNU/Linux | 无法直接在服务器端修改数据 |
Samba | 局域网 | Windows、GNU/Linux | Windows、GNU/Linux | 仅限局域网使用 |
NFS | 局域网与公网 | GNU/Linux | GNU/Linux | 大多数情况下都在 GNU/Linux 之间的机器上使用 |
优点:
- 配置简单
缺点:
- NFS 会将客户端操作系统里的用户 UID 映射到服务器的 UID 上,在权限上不够清晰,需要使用者足够了解 GNU/Linux 的用户管理和权限管理。
RPC 服务
NFS 需要依赖 RPC 服务才能被正常使用。
NFS 端口占用:2049
RPC 端口占用:111
NFS Daemon 端口占用:随机
众所周知,要访问服务必须知道服务的端口,但是,NFS Daemon 的端口是随机的,怎么办呢? RPC 的 111 端口是固定的。换言之,当客户端访问时,其实就是找 RPC 服务。NFS 是被 RPC 服务管理的,当您启动了 NFS 服务,所有的主进程以及子进程都会在 RPC 这里注册,相当于明确告知 RPC 服务 NFS 所使用的主进程端口 2049 以及子进程的端口。
NFS 的权限说明
NFS 本身不需要再单独创建特有的用户且没有身份验证机制,所以当客户端的身份成功映射到服务器端之后,需要使用者明确知道映射关系,以方便确认权限问题。和 Samba、FTP 一样,NFS 要想使一个功能生效,不仅与 NFS 服务的配置文件有关,还与操作系统目录的权限有关,只有两个都配置正确才能使功能生效,如果有其中任意一个没有正确配置,GNU/Linux 会取最严格的权限。
将客户端的身份映射到服务端上,那么,就会有四种情况出现。
第一种情况
客户端和服务器端上刚好都有相同的账户和用户组,此时的用户名与 UID 刚好一致。内核只认识 UID,而且在权限的分配上,也是绑定到 UID 上的。
比如客户端上的登陆身份是 tk(uid=1000),服务器上的身份也是 tk(uid=1000),极少极少的情况会出现客户端和服务器的用户名、UID、密码都是一样的情况,在实验环境下可能出现,但是实际的工作中几乎不可能出现。
第二种情况
客户端和服务器端拥有相同的 UID,但是用户名不一样。这是比较容易出现的一种情况,比如客户端有用户为 a1(uid=1000),服务器有用户为b1(uid=1000),在客户端上访问服务器端的 NFS 共享目录时,身份会被识别为 b1,因为权限绑定在 UID 上。
比如说服务器共享的 NFS 目录是 /nfs_share,客户端需要挂载共享目录才能正常使用,假设这个挂载目录为 /s_nfs,客户端查看 /s_nfs 权限时所有者所属组为 a1,而在服务器上查看 /nfs_share 目录时,所有者所属组为 b1,这就很容易混淆。
第三种情况
服务器端上没有客户端的 UID,服务器会把客户端的用户自动映射为数字用户(不显示用户名)
第四种情况
客户端使用 root 用户(uid=0)访问服务器端的 NFS共享,则服务器端自动映射为 nobody 用户,原因在于使用 root 用户不够安全。当然,服务器端可以通过修改配置文件的方式将 root 映射为 root。
NFS 服务器端的安装、配置和管理
在 RockyLinux 8 上,您可以执行以下命令来安装 NFS 的服务器端:
Shell > dnf -y install rpcbind nfs-utils
配置文件:/etc/exports,默认情况下其内容为空。
相关守护进程:nfs-server.service 和 rpcbind.service。在启动时,您需要首先启动 rpcbind.service
将这两个守护进程启动,其输出内容如下:
Shell > systemctl start rpcbind.service nfs-server.service
Shell > ps -lef | grep -i -E "rpc|nfs"
1 I root 1661 2 0 60 -20 - 0 - 14:01 ? 00:00:00 [rpciod]
4 S rpc 34461 1 0 80 0 - 16832 - 14:06 ? 00:00:00 /usr/bin/rpcbind -w -f
5 S rpcuser 34467 1 0 80 0 - 11311 core_s 14:06 ? 00:00:00 /usr/sbin/rpc.statd
1 S root 34470 1 0 80 0 - 15847 do_epo 14:06 ? 00:00:00 /usr/sbin/rpc.idmapd
5 S root 34475 1 0 80 0 - 12566 do_epo 14:06 ? 00:00:00 /usr/sbin/nfsdcld
1 S root 34477 1 0 80 0 - 13748 core_s 14:06 ? 00:00:00 /usr/sbin/rpc.mountd
1 S root 34485 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34486 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34487 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34488 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34489 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34490 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34491 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
1 S root 34492 2 0 80 0 - 0 - 14:06 ? 00:00:00 [nfsd]
0 S root 34511 1447 0 80 0 - 55505 - 14:06 pts/0 00:00:00 grep --color=auto -i -E rpc|nfs
rpcbind:RPC 的守护进程。
rpc.statd:这个进程实现了网络状态监控 (NSM) 的 RPC 协议,通知 NFS 客户端什么时候一个NFS服务器非正常重启动。
rpc.mountd:处理客户端挂载。
rpc.rquotad:NFS配额,用来限制用户使用空间大小。
rpc.idmapd:NFS v4 名称映射守护进程,使用 /etc/idmapd.conf 的配置文件。当请求加载 nfsv4 时,该守护进程将处理 UID 和 GID 映射。
nfsd:NFS守护进程。
配置 /etc/exports
这个文件的书写格式为:
共享目录 客户端(权限)
共享目录:键入共享目录的路径。若您需要将这个目录给多个客户端共享,在 「客户端(权限)」 后面空格隔开再写一个客户端即可。
客户端:将目录提供给那个或哪一类客户端使用。可以是单个 IP 地址、主机名、网段等。例如:
192.168.100.2
192.168.20.0/24
192.168.20.0/255.255.255.0
example.com
*
权限:这里的权限指的就是 NFS 服务权限,常见权限如下:
权限 | 含义 |
---|---|
rw | 读写 |
ro | 只读 |
all_squash | 将所有客户端的用户都映射为 nobody |
root_squash | 将客户端的 root 映射为 nobody |
no_root_squash | 不将客户端的 root 映射为 nobody,即允许客户端的 root 映射为服务器端的 root。不推荐开启,安全风险较高 |
anonuid | 将所有客户端的用户都映射为指定的 UID 用户身份 |
anongid | 将所有客户端端的用户都映射为指定的 GID 组身份 |
sync | 将数据同步写到内存和磁盘中,效率较低但可以保证数据的一致性 |
async | 将数据先保存在内存中,必要时再写入到磁盘中 |
更多权限说明请参考 man 5 exports
配置示例
场景一:任何人都可以访问 NFS,且允许 root 访问。可填写为 – /home/test *(rw,no_root_squash),需要注意 /home/test 需要有 w 权限。
场景二:同时共享多个目录,一个目录有多个客户端。你可以填写以下举例内容,这是两行内容
/home/test 192.168.20.5(rw,no_root_squash) *(ro)
/home/sof 192.168.20.0/24(rw)
场景三:匿名用户访问。只写 all_squash 表示映射为 nobody 用户,若后面有 anonuid=1000 ,表示所有登录用户都映射为 UID=1000 的用户。
/home/nfsdir 192.168.20.0/24(rw,all_squash,anonuid=1000)
相关命令
您可以通过 rpcinfo
命令来查看 RPC 服务的注册信息,用法为 rpcinfo -p [IP|Hostname]
,直接键入 rpcinfo -p
表示查阅本机的 RPC 注册信息。
Shell > rpcinfo -p
program vers proto port service
100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100000 4 udp 111 portmapper
100000 3 udp 111 portmapper
100000 2 udp 111 portmapper
100024 1 udp 41093 status
100024 1 tcp 51449 status
100005 1 udp 20048 mountd
100005 1 tcp 20048 mountd
100005 2 udp 20048 mountd
100005 2 tcp 20048 mountd
100005 3 udp 20048 mountd
100005 3 tcp 20048 mountd
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100227 3 tcp 2049 nfs_acl
100021 1 udp 43009 nlockmgr
100021 3 udp 43009 nlockmgr
100021 4 udp 43009 nlockmgr
100021 1 tcp 40475 nlockmgr
100021 3 tcp 40475 nlockmgr
100021 4 tcp 40475 nlockmgr
与 NFS 相关的命令是 exportfs
命令,常见选项有:
-a
– 按照配置文件挂载或卸载所有 NFS 共享目录-r
– 重新挂载 NFS 共享目录-u
– 卸载 NFS 共享目录-v
– 显示详细信息
例如 exportfs -arv
表示重新挂载所有 NFS 共享目录,不用重启NFS服务。 exportfs -auv
表示卸载所有 NFS 共享目录。
showmount
命令用来查看 NFS 共享目录,用法为 showmount -e [IP | Hostname]
,客户端与服务器端都可以使用这个命令。
客户端的使用
角色 | IP 地址 |
---|---|
服务器端 | 192.168.100.20/24 |
客户端 | 192.168.100.21/24 |
服务器端的 /etc/exports 文件内容如下:
Shell > cat /etc/exports
/home/test 192.168.100.21(rw,no_root_squash)
/home/soft 192.168.100.21(rw)
Shell > exportfs -arv
exporting 192.168.100.21:/home/soft
exporting 192.168.100.21:/home/test
客户端要正常使用 NFS 服务,也需要启动 rpcbind 服务:
Shell > systemctl start rpcbind.service
Shell > showmount -e 192.168.100.20
Export list for 192.168.100.20:
/home/soft 192.168.100.21
/home/test 192.168.100.21
前面提到,使用 NFS 服务是需要客户端进行挂载的,步骤是:
-
建立挂载点。挂载点即空目录
-
客户端进行挂载。
Shell > mkdir /home/{test,soft} Shell > mount -t nfs 192.168.100.20:/home/test /home/test Shell > mount -t nfs 192.168.100.20:/home/soft /home/soft Shell > df -hT 文件系统 类型 大小 已用 可用 已用% 挂载点 ... 192.168.100.20:/home/test nfs4 47G 15G 31G 32% /home/test 192.168.100.20:/home/soft nfs4 47G 15G 31G 32% /home/soft
Fedora 我使用的是 root 用户进行登录。由于 /home/soft 没有 no_root_squash 权限,意味着客户端的 root 用户会被映射为服务器端的 nobody 用户。nobody 对于 /home/soft/ 目录来说,没有 w 权限,因此不能创建文件。
Shell(192.168.100.20) > ls -ld /home/soft/ drwxr-xr-x 2 root root 4096 12月 4 14:58 /home/soft/
Shell(192.168.100.21) > cd /home/soft Shell(192.168.100.21) > touch aa bb cc touch: 无法 touch 'aa': 权限不够 touch: 无法 touch 'bb': 权限不够 touch: 无法 touch 'cc': 权限不够
更改目录的所有者即可:
Shell(192.168.100.20) > chown nobody /home/soft/ Shell(192.168.100.21) > touch /home/soft/{aa,bb,cc} Shell(192.168.100.20) > ls -l /home/soft/ -rw-r--r-- 1 nobody nobody 0 12月 4 15:22 aa -rw-r--r-- 1 nobody nobody 0 12月 4 15:22 bb -rw-r--r-- 1 nobody nobody 0 12月 4 15:22 cc
对于 /home/test 用户来说,客户端的 root 会映射为服务器端的 root,拥有 w 权限即可创建文件
Shell(192.168.100.20) > ls -ld /home/test/ drwxr-xr-x 2 root root 4096 12月 4 14:58 /home/test/ Shell(192.168.100.21) > touch /home/test/{file1,file2} Shell(192.168.100.20) > ls -l /home/test/ -rw-r--r-- 1 root root 0 12月 4 15:27 file1 -rw-r--r-- 1 root root 0 12月 4 15:27 file2
-
卸载。
当客户端不再需要 NFS 的共享目录后,卸载挂载点即可:
Shell(192.168.100.21) > umount /home/test /home/soft
-
开机自启动
如果客户端挂载的共享目录需要开机自启动,需要写入到 /etc/fstab 文件当中。比如说这样的一个例子 ——
192.168.100.20:/home/test /home/test nfs defaults 0 0
四种情况的模拟
第一种情况
客户端和服务器都有相同的UID、用户名、所属组和密码。这种情况下,客户端是什么用户登陆,服务器端就是什么。我们可以模拟:
先在服务器端创建新用户:
Shell(192.168.100.20) > useradd -u 2000 test1
Shell(192.168.100.20) > passwd test1
实验环境下,为了让所有的用户都拥有 w 权限,将这两个共享目录的权限设置为 777:
Shell(192.168.100.20) > chmod 777 /home/test/ /home/soft/
Shell(192.168.100.20) > ls -ld /home/test/ ; ls -ld /home/soft/
drwxrwxrwx 2 root root 4096 12月 4 15:27 /home/test/
drwxrwxrwx 2 nobody root 4096 12月 4 15:22 /home/soft/
接着在客户端创建同名、同密码的用户 test1,并执行相关的操作:
Shell(192.168.100.21) > useradd -u 2000 test1
Shell(192.168.100.21) > passwd test1
Shell(192.168.100.21) > showmount -e 192.168.100.20
Export list for 192.168.100.20:
/home/soft 192.168.100.21
/home/test 192.168.100.21
Shell(192.168.100.21) > mount -t nfs 192.168.100.20:/home/test /home/test
Shell(192.168.100.21) > df -hT
文件系统 类型 大小 已用 可用 已用% 挂载点
...
192.168.100.20:/home/test nfs4 47G 15G 31G 32% /home/test
Shell(192.168.100.21) > su - test1
Shell(192.168.100.21 test1) > cd /home/test/ ; touch u-test1-file1 ; ls -l
-rw-r--r-- 1 test1 test1 0 12月 7日 11:06 u-test1-file1
而在服务器端查看,权限也是属于 test1:
Shell(192.168.100.20) > ls -l /home/test
-rw-r--r-- 1 test1 test1 0 12月 7 11:06 u-test1-file1
第二种情况
客户端和服务器拥有相同的 uid ,但是用户名不同,这是比较容易出现的一种情况。
服务器端这边不做任何修改。
客户端则执行以下操作:
Shell(192.168.100.21) > userdel -r test1
Shell(192.168.100.21) > useradd -u 2000 newuser1
Shell(192.168.100.21) > passwd newuser1
Shell(192.168.100.21) > su - newuser1
Shell(192.168.100.21 newuser1) > cd /home/test/ ; touch newuser1-file ; ls -l
-rw-r--r-- 1 newuser1 newuser1 0 12月 7日 11:15 newuser1-file
再查看服务器端的文件权限情况:
Shell(192.168.100.20) > ls -l /home/test/
-rw-r--r-- 1 test1 test1 0 12月 7 11:15 newuser1-file
第三种情况
服务器没有客户端对应的 uid,自动映射为数字 uid 用户。
服务器端这边不做任何修改。
客户端则执行以下操作:
Shell(192.168.100.21) > useradd -u 3000 cats
Shell(192.168.100.21) > passwd cats
Shell(192.168.100.21) > su - cats
Shell(192.168.100.21 cats) > cd /home/test/ ; touch cats-file ; ls -l
-rw-r--r-- 1 cats cats 0 12月 7日 11:25 cats-file
而在服务器端这边则是:
Shell(192.168.100.20) > ls -l /home/test
-rw-r--r-- 1 3000 3000 0 12月 7 11:25 cats-file
第四种情况
Fedora 我直接用的是 root 用户登录,因此直接使用即可:
Shell(192.168.100.21) > mount -t nfs 192.168.100.20:/home/soft /home/soft
Shell(192.168.100.21) > touch /home/soft/root-file1 /home/test/root-file2
Shell(192.168.100.21) > ls -l /home/soft/root-file1 /home/test/root-file2
-rw-r--r-- 1 nobody nobody 0 12月 7日 11:33 /home/soft/root-file1
-rw-r--r-- 1 root root 0 12月 7日 11:33 /home/test/root-file2
服务器这边则是:
Shell(192.168.100.20) > ls -l /home/soft/ /home/test/
-rw-r--r-- 1 nobody nobody 0 12月 7 11:33 root-file1
-rw-r--r-- 1 root root 0 12月 7 11:33 root-file2