NFS 笔记
Table of Contents
1 NFS 服务端使用记录
1.1 Linux NFS 服务端
1.1.1 安装服务
使用 RH 系发行版:
sudo dnf install nfs-utils
安装nfs-utils
软件包。sudo systemctl enable --now nfs-server
开机自动启动服务器。sudo firewall-cmd --add-service={rpc-bind,mountd,nfs} --permanent
开放端口。sudo firewall-cmd --reload
重载防火墙使添加的服务生效。
使用 Debian 系发行版:
sudo apt install nfs-kernel-server
安装 NFS 服务端。sudo systemctl enable --now nfs-server.service
启动 NFS Server 并设置开机启动。
硬盘挂载方式为 /etc/systemd/system/mnt-hgst3ta.mount
服务:
[Install] WantedBy=multi-user.target [Mount] Options=defaults Type=ext4 What=/dev/disk/by-uuid/cd2949ed-9e14-4a34-a703-6dcbd761e9d3 Where=/mnt/hgst3ta [Unit] Description=Mount 2nd HGST 3T disk under /mnt/hgst3ta.
挂载硬盘到 /mnt/hgst3ta 后 /mnt/hgst3ta 的权限为 drwxr-xr-x. 2 root root 4.0K ...
。
用 sudo chmod 777 /mnt/hgst3ta
对所有用户开放所有权限。
配置文件 /etc/exports 的内容为 /mnt/hgst3ta (rw,sync,root_squash)
。
执行 sudo exportfs -ra
命令根据 /etc/exports 文件重新载入共享配置。
exportfs
常用的选项有:
-r
: 打开或取消所有目录共享。它使 /var/lib/nfs/xtab 和 /etc/exports 同步,将 /etc/exports 中已删除的条目从 /var/lib/nfs/xtab 中删除,将内核共享表中任何不再有效的条目移除。-a
: 根据将其它选项传递给 exportfs 导致所有目录被导出或取消导出。如果没有指定其他选项, exportfs 会导出 /etc/exports 中指定的所有文件系统。-o <file_systems>
: 指定导出没有在 /etc/exports 中列出的目录。格式必须与在 /etc/exports 中的相同。这个选项通常用来测试导出的文件系统,然后再将其永久添加到导出的文件系统列表中。-i
: 忽略 /etc/exports,用命令行给出的选项定义导出的文件系统。-u
: 取消导出所有共享目录。exportfs -ua
命令挂起所有的 NFS 共享,同时保持所有 NFS 服务。exportfs -r
可新启用 NFS 共享。
-v
: 在执行 exportfs 命令时,详细显示要导出或取消导出的文件系统。
1.1.2 exports 常用配置参数
/etc/exports 管理 NFS 的共享配置,每个条目都有以下结构:
export host(options) export host1(options1) host2(options2) host3(options3) export *(options) /mnt/hgst8ta *(rw,async,root_squash,no_subtree_check) /mnt/hgst3ta *(rw,async,root_squash,no_subtree_check)
配置的选项有:
ro
:read-only
远程主机无法更改文件系统中共享的数据。rw
:read-write
远程主机可以更改文件系统中共享的数据。sync
: 同步写入。在数据写入磁盘前,NFS 服务器不返回写入成功。async
: 异步写入。在数据写入磁盘前,NFS 服务器返回写入成功。wdelay
: 如果 NFS 服务器预期另外一个写入请求即将发生,则 NFS 服务器会延迟写入磁盘。它减少了必须使用独立写入命令访问磁盘的次数,从而减少写入开销。要禁用此选项,指定no_wdelay
选项,该选项仅在同时指定默认同步选项时才可用。root_squash
挂载 NFS 目录的用户如果是 root 那么这个用户的权限将被压缩成为匿名用户,相应的 UID 与 GID 都会变成 nobody 系统账号的身份。no_root_squash
挂载 NFS 目录的用户如果是 root 那么对于这个共享目录来说,挂载方具有 root 权限。 这个特性有安全问题,不建议用。all_squash
挂载 NFS 目录的所有用户均被压缩成为匿名用户,即以nobody
用户的身份登录。anonuid
和anongid
明确指定 NFS 服务器上用户的 uid 和 gid,挂载方的用户必须拥有相同的 uid 和 gid 才能正常访问 NFS 目录。配置写成export host(anonuid=uid,anongid=gid)
这样的。secure
限制挂载方只能从小于 1024 的 tcp/ip 端口连接 NFS 服务器 ( 默认设置 )。改为insecure
允许客户端从大于 1024 的 tcp/ip 端口连接服务器。subtree_check
若输出目录是一个子目录,则 NFS 服务器将检查其父目录的权限。no_subtree_check
即使输出目录是一个子目录,NFS 服务器也不检查其父目录的权限。
如果服务器支持 NFSv3 则客户端使用 sudo showmount --exports <server-ip>
查看有哪些共享目录。
如果服务器支持 NFSv4 则客户端可以直接挂载根目录后进行查找:
mount <my-server>:/ /mnt/ ls /mnt/
1.1.3 仅开启 NFSv4
NFSv4 只需要 TCP/UDP 2049
一个端口,也不需要 portmap
这个包。
首先把 /etc/default/nfs-common 内容修改为:
# If you do not set values for the NEED_ options, they will be attempted # autodetected; this should be sufficient for most people. Valid alternatives # for the NEED_ options are "yes" and "no". # Do you want to start the statd daemon? It is not needed for NFSv4. NEED_STATD="no" # Options for rpc.statd. # Should rpc.statd listen on a specific port? This is especially useful # when you have a port-based firewall. To use a fixed port, set this # this variable to a statd argument like: "--port 4000 --outgoing-port 4001". # For more information, see rpc.statd(8) or http://wiki.debian.org/SecuringNFS STATDOPTS= # Do you want to start the idmapd daemon? It is only needed for NFSv4. NEED_IDMAPD="yes" # Do you want to start the gssd daemon? It is required for Kerberos mounts. NEED_GSSD=
然后把 /etc/default/nfs-kernel-server 内容修改为:
# Number of servers to start up RPCNFSDCOUNT=8 # Runtime priority of server (see nice(1)) RPCNFSDPRIORITY=0 # Options for rpc.mountd. # If you have a port-based firewall, you might want to set up # a fixed port here using the --port option. For more information, # see rpc.mountd(8) or http://wiki.debian.org/SecuringNFS # To disable NFSv4 on the server, specify '--no-nfs-version 4' here RPCMOUNTDOPTS="--manage-gids -N 2 -N 3" # Do you want to start the svcgssd daemon? It is only required for Kerberos # exports. Valid alternatives are "yes" and "no"; the default is "no". NEED_SVCGSSD="" # Options for rpc.svcgssd. RPCSVCGSSDOPTS="" RPCNFSDOPTS="-N 2 -N 3"
NFSv4 中的 rpcbind
已经没有用了,但它依旧会随 nfs-server.service
启动。最后需要停掉它们:
sudo systemctl mask rpcbind.socket sudo systemctl mask rpcbind.service
1.2 FreeBSD NFS 服务端
1.2.1 启动服务
FreeBSD 系统内置了 NFS 的服务端与客户端,所以不需要安装其他的包。
让 NFS 服务开机自启动,需要在 /etc/rc.conf 里添加:
rpcbind_enable="YES" nfs_server_enable="YES" nfs_server_flags="-u -t -n 4" mountd_flags="-r" # 开启 nfsv4 nfsv4_server_enable="YES" nfsuserd_enable="YES"
注: 只要 nfs_server_enable
被设置为 "YES"
, mountd
就能自动运行。
要让被导出的文件系统能被支持 NFS v4 协议的 client 挂载,还要在 /etc/exports 里面加入:
V4: /
用 root 权限执行下面的命令,可立即启动 NFS 服务:
rpcbind nfsd -u -t -n 4 mountd -r
修改 /etc/exports 文件后,必须让 mountd 服务根据新的内容重新生成配置。一种方法是通过给正在运行的服务程序发送 HUP
信号来完成:
# root kill -HUP `cat /var/run/mountd.pid` # 普通用户 sudo kill -HUP `sudo cat /var/run/mountd.pid`
或指定适当的参数来运行 mountd rc(8) 脚本:
/etc/rc.d/mountd onereload
1.2.2 exports 常用配置参数
比如,指定两个 client 操作服务器数据时具有 lsz 用户的身份,其他 client 只能读取:
V4: / /mnt/mymir2/data -alldirs -mapall=lsz 192.168.1.20 /mnt/mymir2/data -alldirs -mapall=lsz 192.168.1.30 /mnt/mymir2/data -alldirs -mapall=lsz -ro /mnt/mymir2/videos -alldirs -mapall=lsz 192.168.1.20 /mnt/mymir2/videos -alldirs -mapall=lsz 192.168.1.30 /mnt/mymir2/videos -alldirs -mapall=lsz -ro
V4: /
表示在/
路径下的所有 NFS share 都能被 client 以 NFS v4 协议挂载。-ro
表示read only
所有挂载此 NFS share 的 client 不能做读取之外的其他操作。-maproot=user
如果 client 以 root 身份操作服务器,那么所有服务器的操作会交由本机的 user 来执行。-mapall=user
所有 client 的操作都交由本机 user 用户执行。-alldirs
client 可以将 NFS share 的任意子目录设为挂载点。即,如果在 /etc/exports 导出 /usr 目录,那么 client 可以挂载 /usr/include 目录。-network {IP}
和-mask {MASK}
指定允许连接的 IP 段。
1.2.3 ZFS 的坑
1.2.3.1 不推荐使用 ZFS 的 sharenfs 功能
Solaris 上 ZFS 的 sharenfs 可以直接操作内核里的 NFS。但在 FreeBSD 上,sharenfs 做的是把配置写入 /etc/zfs/exports 再使用 FreeBSD 的 NFS 服务器根据这个文件重新生成导出配置。
但是 FreeBSD ZFS 上这样的 sharenfs 操作有时会出一些奇怪的问题。至少在 FreeBSD 13 还没解决。另外,FreeBSD 用的是 ZOL ( ZFS On Linux ) 而不是 Solaris 的 ZFS 代码,我猜这可能是问题的起因吧。
虽然对于一些简单的 NFS share 使用 sharenfs 没什么问题,但还是不建议用它。
使用传统的 exports(5) 文件是最稳妥的选择。
1.2.3.2 嵌套挂载的 zfs 文件系统需要分别导出
现在有这么一个 zpool:
pool: mymir2 state: ONLINE scan: resilvered 2.46T in 06:52:59 with 0 errors on Sun Aug 15 17:50:49 2021 config: NAME STATE READ WRITE CKSUM mymir2 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 da4 ONLINE 0 0 0 da5 ONLINE 0 0 0 errors: No known data errors
在这个 zpool 上有这些 zfs 文件系统:
% zfs list NAME USED AVAIL REFER MOUNTPOINT mymir2 2.55T 81.1G 104K /mnt/mymir2 mymir2/data 99.7G 81.1G 99.7G /mnt/mymir2/data mymir2/videos 2.46T 81.1G 2.46T /mnt/mymir2/videos
也就是说,以 mymir2 为根节点的树上,有 3 个节点,其中 mymir2/data 和 mymir2/videos 为两个同级的叶子节点。
此时要导出整个 mymir2 根节点 ( 即客户端挂载根节点的 NFS share 后可以直接操作表现为两个文件夹的两个叶子节点 ),那么如果在 /etc/exports 里写:
/mnt/mymir2 -alldirs -maproot=root -network 192.168.1.0 -mask 255.255.255.0
执行 kill -HUP mountd
重载配置文件之后,在客户端 ( 比如 windows ) 使用 mount -o nolock -o mtype=hard -o timeout=60 \\192.168.1.10\mnt\mymir2 K:\
进行挂载。
此时在 windows 上的 K:\ 路径下只会看到 data 和 videos 两个空文件夹。这意味着,对应的 mymir2/data 和 mymir2/videos 两个子文件系统 ( 叶子节点 ) 并没有被 NFS share 导出。对于 K:\data 和 K:\videos 的读写操作会直接作用在 mymir2 这个根节点上,不会进入叶子节点。
如果想要导出一个根节点和两个叶子节点 ( 一共 3 个 zfs 文件系统 ),只能在 /etc/exports 里这样写,分别导出:
/mnt/mymir2 -alldirs -maproot=root -network 192.168.1.0 -mask 255.255.255.0 /mnt/mymir2/data -alldirs -maproot=root -network 192.168.1.0 -mask 255.255.255.0 /mnt/mymir2/videos -alldirs -maproot=root -network 192.168.1.0 -mask 255.255.255.0
每个 exports 项只能导出一个文件系统。挂载时,也只能分别将导出的文件系统挂载到不同的挂载点。
2 NFS 客户端使用记录
2.1 踩坑
2.1.1 客户端挂载后无法读写
挂载点为 /mnt/hgst3ta,权限为 drwxr-xr-x. 2 root root 4.0K ...
。
/etc/exports 共享配置为 /mnt/hgst3ta *(rw,sync,root_squash)
。
因为客户端用户的 uid 和 gid 都是 1000,对应在 NFS 服务器上的 1000:1000 用户不能操作 /mnt/hgst3ta 文件夹,所以客户端的 1000:1000 用户也没有权限操作这个 NFS 共享。
解决方案有两个:
sudo chmod 777 /mnt/hgst3ta
让所有用户都可读写。sudo usermod -aG <username-with-uid-1000> root
把这个用户加入 root 用户组,再sudo chmod 774 /mnt/hgst3ta
让用户组有读写权限。
注意: 第一个配置会使文件夹对所有用户开放,任何挂载 /mnt/hgst3ta 的用户都可以修改文件夹中的文件。
2.2 Linux 客户端
使用 RH 系发行版: sudo dnf install nfs-utils
安装 nfs-utils
软件包。
使用 Debian 系发行版: sudo apt install nfs-common
安装 NFS 客户端与服务端。
注: 网上教程也有说用 sudo apt install nfs-client
只安装客户端就行。但是自从 Debian 11 开始的软件库里不再有 nfs-client
, sudo apt install nfs-client
会被自动定向到安装 nfs-common
。
sudo showmount 192.168.1.10 -e
查看服务器共享了哪些文件夹。
在客户机上用 sudo mount -t nfs -o nfsvers=4 192.168.1.10:/mnt/hgst3ta ~/NetworkStorage/hgst3ta/
挂载。
注: man nfs
可以查看所有的挂载选项。
用 sudo umount 192.168.1.10:/mnt/hgst3ta
卸载。
可以创建 ~/.config/systemd/user/mnt-r6-FreeBSDa-hgst3ta.service 在用户登入时执行挂载的 .service 文件。内容如下:
[Unit] Description=Mount r6 vm100 2nd HGST 8T disk under %h/NetworkStorage/hgst3ta/. [Service] ExecStart=sudo mount.nfs4 192.168.1.10:/mnt/hgst3ta %h/NetworkStorage/hgst3ta/ ExecStop=sudo umount 192.168.1.10:/mnt/hgst3ta RemainAfterExit=yes [Install] WantedBy=default.target
systemctl --user enable mnt-r6-FreeBSDa-hgst3ta.service
在用户登入后自动执行。
2.3 FreeBSD 客户端
FreeBSD 系统内置了 NFS 的服务端与客户端,所以不需要安装其他的包。
让 NFS 客户端开机自启动,需要在 /etc/rc.conf 里添加:
nfs_client_enable="YES"
用 root 权限执行 nfsiod -n 4
可立即启动 NFS 客户端。
mount <ip>:/<shared_path> /<path_to_mount>
挂载 NFS 共享。
要让 NFS share 在系统启动时自动挂载,则需要在 /etc/fstab 文件中添加:
<ip>:/<shared_path> /<path_to_mount> nfs rw 0 0
注: man mount_nfs
可以查看所有的挂载参数
2.4 Windows 客户端
Windows 只能把 NFS 共享挂载在某个驱动器号下,不能挂载在某个文件夹下。
按 Win+R 输入 OptionalFeatures 回车,勾选 NFS 服务 -> NFS 客户端 。
不需要勾选 管理工具 ,那玩意是给 windows server 用的,非 Windows Server 只能靠 映射网络驱动器 挂载 NFS。
列出被 NFS 服务器导出的文件夹:
showmount -e [server]
显示 NFS 服务器导出的所有共享。showmount -a [server]
列出客户端主机名或 IP 地址,以及使用“主机:目录”格式显示的安装目录。showmount -d [server]
显示 NFS 服务器上当前由某些 NFS 客户端安装的目录。
按 Win+R 输入 regedit 回车,进入路径为 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default 的注册表,新建两个 DWORD(32位) 注册表项:
- 数值名称为:
AnonymousUID
,数值数据为: NFS 服务器上对应的 UID 值,基数为十进制值。 - 数值名称为:
AnonymousGID
,数值数据为: NFS 服务器上对应的 GID 值,基数为十进制值。
针对 windows 挂载 NFS 共享后可能出现乱码的情况,需要在 控制面板 -> 时钟和区域 -> 区域 -> 管理 -> 非 Unicode 程序的语言 -> 更改系统区域设置 -> 给 Beta 版: 使用 Unicode UTF-8 提供全球语言支持 打勾 -> 重启。
最后打开 CMD ( 不是 PowerShell ) 执行 mount -o nolock -o mtype=hard -o timeout=60 \\{ip}\{path_to_share} K:\
进行挂载。
注: 执行 mount -h
可以查看所有的挂载选项。
除了使用 mount 命令也可使用 net use
命令来挂载 NFS 共享,比如这样:
net use P: \\192.168.1.10\mnt\hgst8ta net use Q: \\192.168.1.10\mnt\hgst3ta