Rocky Linux 9 NFS 完整学习笔记:原理、配置、自动挂载与实操实验

简介

NFS(Network File System,网络文件系统)是一种让客户端通过网络访问远程服务器目录的文件系统协议。

它和 scprsync 最大的区别是:

1
2
3
4
scp / rsync
客户端 ──复制/同步──> 服务端

两边各有文件

而 NFS 是:

1
2
3
4
5
6
7
8
客户端

│ 网络文件系统访问

NFS Server


真实文件系统

客户端把服务端的目录挂载到本地以后,使用体验和本地目录非常接近。

例如服务端:

1
2
3
4
Hostname: rocky-pi
IP: 192.168.0.50
用户: rocky
共享目录: /srv/nfs/lab

客户端把它挂载到:

1
/mnt/nfs-lab

之后访问:

1
cat /mnt/nfs-lab/hello.txt

实际上访问的是服务器上的:

1
/srv/nfs/lab/hello.txt

这不是文件复制,而是客户端通过 NFS 协议实时访问远程文件系统。

本篇使用如下实验环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
操作系统:Rocky Linux 9
Hostname:rocky-pi
IP:192.168.0.50
用户:rocky
SSH:已配置免密登录

NFS Server:
192.168.0.50

NFS 共享目录:
/srv/nfs/lab

Linux Client 挂载目录:
/mnt/nfs-lab

实验默认局域网网段:

1
192.168.0.0/24

可以通过:

1
ip route

确认。

例如:

1
2
default via 192.168.0.1 dev eth0
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.50

详解

一、NFS 的核心工作模型

NFS 本质上是 Client/Server 模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     NFS Client

│ read/write/open

NFS Client Kernel

│ RPC / TCP

网络传输


NFS Server


Linux VFS 层


XFS / ext4 / 其他文件系统


实际磁盘

应用程序并不需要知道文件位于远程服务器。

例如:

1
vim /mnt/nfs-lab/test.txt

对于 vim 来说,它只是打开了一个普通文件。

实际上 Linux 内核会把文件操作转换为 NFS 请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
vim

open()

Linux VFS

NFS Client

TCP/IP

NFS Server

服务器文件系统

因此 NFS 可以让多个服务器共享同一份文件。

典型用途包括:

1
2
3
4
5
6
7
共享配置文件
共享静态资源
共享备份目录
共享软件包
虚拟化存储
集群共享目录
开发测试环境共享文件

二、NFS 与 rsync、scp 的区别

scp 是文件传输:

1
A ──────> B

文件复制完成后,A 和 B 各自拥有独立副本。

rsync 是同步:

1
A ──比较差异──> B

它更适合:

1
2
3
4
备份
镜像同步
发布文件
增量同步

NFS 则不同:

1
2
3
Client

└──────────────> Server File System

客户端看到的是服务端的同一份文件。

因此:

1
2
3
scp / rsync = 数据传输

NFS = 远程文件系统访问

三、NFS Server 与 Client

在 Linux 中,NFS Server 负责:

1
2
3
4
导出目录
控制哪些客户端可以访问
控制读写权限
处理 NFS 请求

客户端负责:

1
2
3
4
发现 NFS Server
挂载远程目录
执行文件读写
处理缓存和重试

在 Rocky Linux 9 中,NFS 相关工具主要来自:

1
nfs-utils

安装:

1
sudo dnf install -y nfs-utils

其中常见命令包括:

1
2
3
4
5
exportfs
showmount
nfsstat
mount.nfs
rpcinfo

四、NFSv3 与 NFSv4

NFSv3 与 NFSv4 在架构上差别很明显。

NFSv3 依赖多个 RPC 服务:

1
2
3
4
5
6
7
8
9
Client

├──── 111 ───── rpcbind

├──── xxxx ──── mountd

├──── xxxx ──── lockd

└──── 2049 ──── nfsd

其中一些 RPC 服务使用动态端口,因此防火墙配置相对复杂。

NFSv4 将很多能力整合到了协议本身:

1
2
3
4
5
Client

│ TCP 2049

NFS Server

因此现代 Linux 环境应该重点掌握 NFSv4。

Rocky Linux 9 可以通过:

1
cat /proc/fs/nfsd/versions

查看 Server 支持的版本。

例如:

1
+3 +4 +4.0 +4.1 +4.2

其中:

1
2
3
4
+3    支持 NFSv3
+4 支持 NFSv4
+4.1 支持 NFSv4.1
+4.2 支持 NFSv4.2

客户端挂载时可以指定:

1
-o vers=3

或者:

1
-o vers=4.2

五、/etc/exports

NFS Server 最重要的配置就是 export。

传统配置文件:

1
/etc/exports

也可以使用:

1
/etc/exports.d/

例如:

1
/etc/exports.d/lab.exports

配置:

1
/srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)

格式:

1
共享目录 客户端范围(参数)

拆开来看:

1
/srv/nfs/lab

表示要共享的目录。

1
192.168.0.0/24

表示整个:

1
192.168.0.x

网段都允许访问。

1
rw

表示协议层允许读写。

1
sync

表示写请求同步提交。

1
root_squash

表示客户端 root 不会直接成为服务器 root。

注意:

1
192.168.0.0/24(rw)

客户端地址和括号之间不要添加空格。


六、常用 exports 参数

rw

允许读写:

1
rw

ro

只读:

1
ro

sync

同步写入:

1
sync

Server 在数据真正提交之后才返回成功。

优点是数据一致性更好。

async

异步:

1
async

可能提高性能,但是服务器突然宕机时存在更高的数据丢失风险。

root_squash

默认推荐:

1
root_squash

客户端:

1
UID=0

不会直接成为 Server:

1
UID=0

而会映射为匿名用户。

no_root_squash

1
no_root_squash

意味着客户端 root 可以作为服务器 root 操作共享文件。

除非明确知道自己在做什么,否则不要使用。

all_squash

1
all_squash

把所有客户端用户都映射为匿名用户。

可以配合:

1
2
anonuid=
anongid=

例如:

1
all_squash,anonuid=1000,anongid=1000

这在客户端 UID/GID 不一致时很有用。


七、NFS 最关键的权限模型:UID/GID

很多第一次学习 NFS 的人会以为:

1
客户端用户名 = 服务端用户名

实际上普通 NFS sec=sys 主要看的是:

1
2
UID
GID

例如 Server:

1
id rocky

得到:

1
uid=1000(rocky) gid=1000(rocky)

Mac 客户端可能:

1
2
uid=501
gid=20

如果 Mac 通过 NFS 创建文件:

1
touch /Volumes/rocky-nfs/mac.txt

Server 上:

1
ls -ln /srv/nfs/lab/mac.txt

可能看到:

1
-rw-r--r-- 1 501 20 ... mac.txt

Server 并不会自动把它变成:

1
rocky:rocky

这就是为什么 NFS 环境中经常要求多台 Linux 主机保持一致的 UID/GID。

企业环境通常会使用:

1
2
3
4
LDAP
Active Directory
FreeIPA
SSSD

实现统一身份。


八、rw 不等于任何人都可以写

假设 exports:

1
/srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)

这里:

1
rw

只是表示:

1
NFS 协议层允许写

最终是否能写,还要继续经过:

1
2
3
4
5
6
7
8
9
NFS rw/ro

UID/GID

Linux owner/group/other 权限

ACL

SELinux

例如目录:

1
drwxrwxrwx /srv/nfs/lab

但是里面有一个文件:

1
-rw-r--r-- 501 20 mac.txt

rocky 用户仍然可能不能修改这个文件。

因为目录权限控制的是:

1
能否创建/删除/遍历目录项

而文件本身的:

1
rw-r--r--

控制文件内容是否可以修改。


九、sudo 与 shell 重定向

一个非常常见的问题:

1
sudo echo "changed by rocky" >> /srv/nfs/lab/mac.txt

可能仍然得到:

1
Permission denied

原因是:

1
sudo echo

只有 echo 以 root 执行。

但是:

1
>>

是当前 shell 在执行。

可以理解成:

1
2
3
4
5
当前用户 shell

├── sudo echo ...

└── 自己负责 >> 文件

因此当前用户没有文件写权限时,重定向仍然失败。

正确方法可以使用:

1
echo "changed by rocky" | sudo tee -a /srv/nfs/lab/mac.txt > /dev/null

或者:

1
sudo sh -c 'echo "changed by rocky" >> /srv/nfs/lab/mac.txt'

不过如果本来的需求就是让 rocky 拥有文件,应该直接调整:

1
sudo chown rocky:rocky /srv/nfs/lab/mac.txt

而不是长期依赖 sudo。


十、NFS、SELinux 和防火墙

NFS Server 不仅受到 /etc/exports 控制,还受到:

1
2
3
firewalld
SELinux
Linux 文件权限

控制。

查看 SELinux:

1
getenforce

正常应该:

1
Enforcing

不要因为 NFS 权限问题直接:

1
setenforce 0

如果怀疑 SELinux:

1
sudo ausearch -m AVC -ts recent

查看目录 SELinux 标签:

1
ls -Zd /srv/nfs/lab

防火墙状态:

1
sudo firewall-cmd --state

NFSv3 实验环境通常开放:

1
2
3
4
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --reload

如果生产环境只使用 NFSv4,则可以进一步减少不必要的 RPC 服务。


十一、Linux 中 mount 到底在哪里看

如果想看系统当前已经挂载的 NFS:

1
findmnt -t nfs,nfs4

这是最推荐的方式。

例如:

1
2
TARGET       SOURCE                         FSTYPE OPTIONS
/mnt/nfs-lab 192.168.0.50:/srv/nfs/lab nfs4 rw,...

也可以:

1
mount | grep nfs

或者:

1
cat /proc/mounts

不过日常排查建议优先:

1
findmnt

如果想看某一个挂载:

1
findmnt /mnt/nfs-lab

十二、fstab 自动挂载

Linux 中传统的开机持久挂载配置文件:

1
/etc/fstab

例如:

1
192.168.0.50:/srv/nfs/lab /mnt/nfs-lab nfs defaults,_netdev,nofail,vers=4.2 0 0

其中:

1
_netdev

表示这是网络文件系统。

1
nofail

表示 NFS Server 无法访问时,不要让系统因此启动失败。

配置以后先不要急着重启。

执行:

1
sudo mount -a

测试配置是否正确。

然后:

1
findmnt /mnt/nfs-lab

确认。


十三、systemd automount

对于网络文件系统,比单纯 /etc/fstab 更推荐的方式之一是:

1
x-systemd.automount

例如:

1
192.168.0.50:/srv/nfs/lab /mnt/nfs-lab nfs defaults,_netdev,nofail,x-systemd.automount,vers=4.2 0 0

此时启动过程中并不会立刻访问 NFS Server。

工作流程:

1
2
3
4
5
6
7
8
9
系统启动

systemd 创建 automount

系统继续正常启动

应用访问 /mnt/nfs-lab

systemd 自动真正挂载 NFS

修改 /etc/fstab 后:

1
sudo systemctl daemon-reload

查看 automount:

1
systemctl list-units --type=automount

对于:

1
/mnt/nfs-lab

systemd 单元通常会编码为:

1
mnt-nfs\x2dlab.automount

查看:

1
systemctl status 'mnt-nfs\x2dlab.automount'

真正挂载后还会有:

1
mnt-nfs\x2dlab.mount

查看:

1
systemctl status 'mnt-nfs\x2dlab.mount'

十四、autofs

autofssystemd automount 是两个不同机制。

安装:

1
sudo dnf install -y autofs

查看:

1
2
rpm -q autofs
systemctl status autofs

autofs 常见配置入口:

1
2
/etc/auto.master
/etc/auto.master.d/

再由 master 文件指向具体 map。

例如:

1
/etc/auto.master.d/nfs.autofs

内容:

1
/nfs /etc/auto.nfs --timeout=60

含义:

1
2
3
4
5
6
7
8
9
10
11
/nfs

└── 自动挂载根目录

/etc/auto.nfs

└── 具体挂载规则

--timeout=60

└── 空闲一定时间后可自动卸载

然后:

1
/etc/auto.nfs

内容:

1
lab -fstype=nfs,rw,vers=4.2 192.168.0.50:/srv/nfs/lab

最终路径:

1
/nfs/lab

当第一次执行:

1
ls /nfs/lab

才真正触发 NFS 挂载。

所以:

1
fstab

适合固定挂载。

1
systemd automount

适合固定目录的按需挂载。

1
autofs

适合大量动态 NFS 目录和自动卸载。


十五、如何判断陌生服务器上的 NFS 是怎么挂载的

先看当前挂载:

1
findmnt -t nfs,nfs4

然后看 /etc/fstab

1
grep -v '^#' /etc/fstab | grep -E 'nfs|nfs4'

检查 systemd automount:

1
systemctl list-units --type=automount

检查 autofs:

1
systemctl status autofs

然后查看 autofs 配置:

1
2
3
4
grep -R -vE '^[[:space:]]*(#|$)' \
/etc/auto.master \
/etc/auto.master.d/ \
/etc/auto.* 2>/dev/null

通过这些命令通常就能确定属于:

1
2
3
4
手工 mount
/etc/fstab
systemd automount
autofs

中的哪一种。


实操实验

实验一:确认实验环境

登录:

1
ssh rocky@192.168.0.50

检查:

1
2
3
4
5
hostname
hostname -I
ip -4 addr
ip route
cat /etc/rocky-release

确认:

1
2
hostname = rocky-pi
IP = 192.168.0.50

实验二:安装 NFS

安装:

1
sudo dnf install -y nfs-utils

确认:

1
rpm -q nfs-utils

实验三:创建共享目录

1
2
3
sudo mkdir -p /srv/nfs/lab
sudo chown rocky:rocky /srv/nfs/lab
sudo chmod 777 /srv/nfs/lab

这里的:

1
777

只用于第一阶段学习,目的是暂时排除 Linux 文件权限干扰。

创建文件:

1
2
3
echo "hello from rocky-pi" > /srv/nfs/lab/hello.txt
date > /srv/nfs/lab/server-time.txt
mkdir -p /srv/nfs/lab/test-dir

检查:

1
ls -lah /srv/nfs/lab

实验四:配置 exports

创建:

1
sudo mkdir -p /etc/exports.d

写入:

1
2
3
sudo tee /etc/exports.d/lab.exports > /dev/null <<'EOF'
/srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)
EOF

查看:

1
cat /etc/exports.d/lab.exports

实验五:启动 NFS Server

1
sudo systemctl enable --now nfs-server

检查:

1
2
3
systemctl status nfs-server --no-pager
systemctl is-enabled nfs-server
systemctl is-active nfs-server

实验六:让 export 配置生效

1
sudo exportfs -rav

查看实际导出规则:

1
sudo exportfs -v

以后每次修改:

1
/etc/exports

或者:

1
/etc/exports.d/*.exports

之后,都可以执行:

1
sudo exportfs -rav

重新加载。


实验七:配置防火墙

检查:

1
sudo firewall-cmd --state

开放实验需要的服务:

1
2
3
4
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --reload

查看:

1
sudo firewall-cmd --list-services

实验八:检查 NFS Server

1
showmount -e localhost

预期:

1
2
Export list for localhost:
/srv/nfs/lab 192.168.0.0/24

查看 RPC:

1
rpcinfo -p localhost

查看 NFS 版本:

1
cat /proc/fs/nfsd/versions

查看端口:

1
sudo ss -ln | grep 2049

实验九:Linux Client 手动挂载 NFS

这里可以让 rocky-pi 自己挂载自己,用于学习客户端逻辑。

创建:

1
sudo mkdir -p /mnt/nfs-lab

挂载:

1
2
3
4
sudo mount -t nfs \
-o vers=4.2 \
192.168.0.50:/srv/nfs/lab \
/mnt/nfs-lab

检查:

1
findmnt /mnt/nfs-lab

或者:

1
mount | grep nfs-lab

再:

1
df -hT | grep nfs

查看文件:

1
ls -lah /mnt/nfs-lab

写入:

1
echo "linux client" > /mnt/nfs-lab/linux-client.txt

检查服务端:

1
cat /srv/nfs/lab/linux-client.txt

实验十:使用 nfsstat

查看挂载参数:

1
nfsstat -m

可能看到:

1
2
3
4
5
6
vers=4.2
rsize=1048576
wsize=1048576
hard
proto=tcp
sec=sys

查看客户端统计:

1
nfsstat -c

查看服务端统计:

1
nfsstat -s

实验十一:NFSv3 与 NFSv4

卸载:

1
sudo umount /mnt/nfs-lab

使用 NFSv3:

1
2
3
4
sudo mount -t nfs \
-o vers=3 \
192.168.0.50:/srv/nfs/lab \
/mnt/nfs-lab

查看:

1
nfsstat -m

确认:

1
vers=3

卸载:

1
sudo umount /mnt/nfs-lab

重新使用 NFSv4.2:

1
2
3
4
sudo mount -t nfs \
-o vers=4.2 \
192.168.0.50:/srv/nfs/lab \
/mnt/nfs-lab

查看:

1
nfsstat -m

确认:

1
vers=4.2

实验十二:理解 UID/GID

查看 rocky

1
id rocky

例如:

1
uid=1000(rocky) gid=1000(rocky)

创建:

1
touch /srv/nfs/lab/rocky-user.txt

查看数字 UID/GID:

1
ls -ln /srv/nfs/lab

应该能看到:

1
1000 1000 rocky-user.txt

如果另外一台客户端 UID 是:

1
501

通过 NFS 创建文件以后,Server 很可能直接显示:

1
501 ...

这说明 NFS 使用的是 UID/GID 身份模型,而不是简单通过用户名匹配。


实验十三:制造 Permission denied

把目录权限恢复得更合理:

1
sudo chmod 775 /srv/nfs/lab

检查:

1
ls -ld /srv/nfs/lab

假设从另一个 UID 不一致的客户端创建:

1
mac.txt

Server 查看:

1
ls -ln /srv/nfs/lab/mac.txt

例如:

1
-rw-r--r-- 1 501 20 ... mac.txt

现在 rocky UID=1000 尝试:

1
echo "changed by rocky" >> /srv/nfs/lab/mac.txt

会得到:

1
Permission denied

原因不是 NFS rw 失效,而是:

1
rocky UID 1000

没有:

1
UID 501

文件的写权限。


实验十四:理解 sudo 重定向问题

执行:

1
sudo echo "changed by rocky" >> /srv/nfs/lab/mac.txt

仍然可能:

1
Permission denied

因为:

1
echo

由 sudo 运行,而:

1
>>

还是当前 shell 在执行。

正确:

1
echo "changed by rocky" | sudo tee -a /srv/nfs/lab/mac.txt > /dev/null

或者:

1
sudo sh -c 'echo "changed by rocky" >> /srv/nfs/lab/mac.txt'

如果文件本来就应该属于 rocky

1
sudo chown rocky:rocky /srv/nfs/lab/mac.txt

然后:

1
echo "changed by rocky" >> /srv/nfs/lab/mac.txt

即可。


实验十五:root_squash

保持 export:

1
/srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)

客户端使用 root 创建文件:

1
sudo touch /mnt/nfs-lab/root-test.txt

观察:

1
ls -ln /srv/nfs/lab/root-test.txt

客户端 root 不应该简单变成 Server root。

这就是:

1
root_squash

保护机制。


实验十六:all_squash

获取 Rocky 用户 UID/GID:

1
2
3
4
5
ROCKY_UID=$(id -u rocky)
ROCKY_GID=$(id -g rocky)

echo "$ROCKY_UID"
echo "$ROCKY_GID"

修改:

1
2
3
sudo tee /etc/exports.d/lab.exports > /dev/null <<EOF
/srv/nfs/lab 192.168.0.0/24(rw,sync,all_squash,anonuid=${ROCKY_UID},anongid=${ROCKY_GID})
EOF

应用:

1
sudo exportfs -rav

此时所有客户端用户通过 NFS 创建文件,都映射为:

1
rocky:rocky

验证:

1
2
touch /mnt/nfs-lab/all-squash-test.txt
ls -ln /srv/nfs/lab/all-squash-test.txt

实验结束后恢复:

1
2
3
4
5
sudo tee /etc/exports.d/lab.exports > /dev/null <<'EOF'
/srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)
EOF

sudo exportfs -rav

实验十七:只读 export

修改:

1
2
3
sudo tee /etc/exports.d/lab.exports > /dev/null <<'EOF'
/srv/nfs/lab 192.168.0.0/24(ro,sync,root_squash)
EOF

应用:

1
sudo exportfs -rav

读取:

1
cat /mnt/nfs-lab/hello.txt

正常。

尝试写:

1
touch /mnt/nfs-lab/readonly-test.txt

应该得到类似:

1
Read-only file system

这里和:

1
Permission denied

含义不同。

1
Read-only file system

优先检查:

1
2
NFS export 是否 ro
mount 是否 ro

而:

1
Permission denied

优先检查:

1
2
3
4
5
UID/GID
chmod
ACL
root_squash
SELinux

恢复:

1
2
3
4
5
sudo tee /etc/exports.d/lab.exports > /dev/null <<'EOF'
/srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)
EOF

sudo exportfs -rav

实验十八:配置 /etc/fstab 开机自动挂载

创建挂载点:

1
sudo mkdir -p /mnt/nfs-lab

备份:

1
sudo cp /etc/fstab /etc/fstab.bak

编辑:

1
sudo vim /etc/fstab

增加:

1
192.168.0.50:/srv/nfs/lab /mnt/nfs-lab nfs defaults,_netdev,nofail,vers=4.2 0 0

测试:

1
sudo mount -a

检查:

1
findmnt /mnt/nfs-lab

如果没有错误,就说明配置有效。


实验十九:systemd automount

/etc/fstab 改成:

1
192.168.0.50:/srv/nfs/lab /mnt/nfs-lab nfs defaults,_netdev,nofail,x-systemd.automount,vers=4.2 0 0

重新加载:

1
sudo systemctl daemon-reload

查看:

1
systemctl list-units --type=automount

访问:

1
ls /mnt/nfs-lab

然后:

1
findmnt /mnt/nfs-lab

可以看到访问目录后才真正挂载。

具体查看 systemd unit:

1
systemctl status 'mnt-nfs\x2dlab.automount'

以及:

1
systemctl status 'mnt-nfs\x2dlab.mount'

实验二十:配置 autofs

如果前面 /etc/fstab 已经挂载 /mnt/nfs-lab,可以保留它,autofs 使用另外一个目录:

1
/nfs/lab

安装:

1
sudo dnf install -y autofs

创建 master 配置:

1
2
3
sudo tee /etc/auto.master.d/nfs.autofs > /dev/null <<'EOF'
/nfs /etc/auto.nfs --timeout=60
EOF

创建 map:

1
2
3
sudo tee /etc/auto.nfs > /dev/null <<'EOF'
lab -fstype=nfs,rw,vers=4.2 192.168.0.50:/srv/nfs/lab
EOF

启动:

1
sudo systemctl enable --now autofs

查看服务:

1
systemctl status autofs

访问:

1
ls /nfs/lab

查看:

1
findmnt /nfs/lab

此时应该可以看到对应 NFS 挂载。

查看 autofs 配置:

1
cat /etc/auto.master

查看:

1
ls -lah /etc/auto.master.d/

查看自定义配置:

1
2
cat /etc/auto.master.d/nfs.autofs
cat /etc/auto.nfs

查看所有非注释配置:

1
2
3
4
grep -R -vE '^[[:space:]]*(#|$)' \
/etc/auto.master \
/etc/auto.master.d/ \
/etc/auto.* 2>/dev/null

实验二十一:观察网络中断

保持 NFS 已挂载。

终端一:

1
2
3
4
5
6
7
cd /mnt/nfs-lab

while true; do
date
ls
sleep 2
done

然后停止 NFS Server:

1
sudo systemctl stop nfs-server

客户端 NFS 操作可能出现等待。

重新启动:

1
sudo systemctl start nfs-server

之后访问恢复。

这是默认:

1
hard

挂载语义的重要表现。

对于重要数据,一般不要为了避免等待就随意使用:

1
soft

因为可能把暂时性的网络故障转化为应用层 I/O 错误。


实验二十二:简单性能实验

测试 NFS 写:

1
2
3
4
5
6
7
cd /mnt/nfs-lab

time dd if=/dev/zero \
of=nfs-test.bin \
bs=1M \
count=100 \
conv=fdatasync

测试服务器本地:

1
2
3
4
5
6
7
cd /srv/nfs/lab

time dd if=/dev/zero \
of=local-test.bin \
bs=1M \
count=100 \
conv=fdatasync

测试完成:

1
2
rm -f /mnt/nfs-lab/nfs-test.bin
rm -f /srv/nfs/lab/local-test.bin

这里的差异可能来自:

1
2
3
4
5
6
7
网络延迟
TCP
NFS RPC
客户端缓存
Server 缓存
磁盘性能
sync 语义

实验二十三:NFS 文件锁

创建锁:

1
2
flock /mnt/nfs-lab/my.lock \
-c 'echo "I have the lock"; sleep 30'

另一个终端:

1
2
flock -n /mnt/nfs-lab/my.lock \
-c 'echo "I got lock"'

第一次通常无法获得锁。

等前面的:

1
30 秒

结束后再次:

1
2
flock -n /mnt/nfs-lab/my.lock \
-c 'echo "I got lock"'

即可获得锁。

这个实验说明 NFS 不只是文件读写,还涉及:

1
2
3
4
文件锁
缓存
一致性
故障恢复

实验二十四:查看一台服务器所有 NFS 配置

查看当前实际挂载:

1
findmnt -t nfs,nfs4

查看 /etc/fstab

1
grep -v '^#' /etc/fstab | grep -E 'nfs|nfs4'

查看 systemd mount:

1
systemctl list-units --type=mount | grep -i nfs

查看 automount:

1
systemctl list-units --type=automount

查看 autofs:

1
systemctl status autofs

查看 autofs 配置:

1
2
3
4
grep -R -vE '^[[:space:]]*(#|$)' \
/etc/auto.master \
/etc/auto.master.d/ \
/etc/auto.* 2>/dev/null

这样基本就可以判断 NFS 是通过:

1
2
3
4
手工 mount
fstab
systemd automount
autofs

哪一种方式挂载。


NFS 常见故障排查

access denied by server

例如:

1
mount.nfs: access denied by server

Server:

1
sudo exportfs -v

检查:

1
cat /etc/exports

以及:

1
cat /etc/exports.d/*.exports

重新加载:

1
sudo exportfs -rav

重点确认客户端 IP 是否在允许范围。


Connection refused

检查:

1
systemctl status nfs-server

端口:

1
sudo ss -ln | grep 2049

防火墙:

1
sudo firewall-cmd --list-all

Permission denied

检查客户端身份:

1
id

检查 Server 文件:

1
ls -ln /srv/nfs/lab

检查整个路径:

1
namei -l /srv/nfs/lab

检查 exports:

1
sudo exportfs -v

检查 SELinux:

1
2
getenforce
sudo ausearch -m AVC -ts recent

排查顺序应该想到:

1
2
3
4
5
6
7
8
9
10
11
UID/GID

文件 owner/group

chmod

ACL

root_squash / all_squash

SELinux

Read-only file system

客户端:

1
nfsstat -m

Server:

1
sudo exportfs -v

重点看是不是:

1
ro

NFS 卡住

检查网络:

1
ping 192.168.0.50

检查 NFS 端口:

1
nc -vz 192.168.0.50 2049

Server:

1
systemctl status nfs-server

如果使用默认 hard mount,Server 暂时不可访问时客户端操作可能等待和重试,这属于 NFS 的正常故障语义之一。


umount 提示 target is busy

先离开目录:

1
cd ~

然后:

1
sudo umount /mnt/nfs-lab

仍然失败:

1
sudo fuser -vm /mnt/nfs-lab

或者:

1
sudo lsof +D /mnt/nfs-lab

找到正在使用挂载点的进程,再处理。


常用命令速查

NFS Server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo systemctl status nfs-server

sudo exportfs -v

sudo exportfs -rav

showmount -e localhost

rpcinfo -p

cat /proc/fs/nfsd/versions

nfsstat -s

sudo ss -ln | grep 2049

NFS Client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
showmount -e 192.168.0.50

sudo mount -t nfs \
-o vers=4.2 \
192.168.0.50:/srv/nfs/lab \
/mnt/nfs-lab

findmnt -t nfs,nfs4

findmnt /mnt/nfs-lab

nfsstat -m

nfsstat -c

df -hT

sudo umount /mnt/nfs-lab

权限排查:

1
2
3
4
5
6
7
8
9
10
11
12
13
id

ls -l

ls -ln

namei -l /srv/nfs/lab

getfacl /srv/nfs/lab

getenforce

sudo ausearch -m AVC -ts recent

自动挂载:

1
2
3
4
5
6
7
8
9
10
11
cat /etc/fstab

systemctl list-units --type=mount

systemctl list-units --type=automount

systemctl status autofs

cat /etc/auto.master

ls -lah /etc/auto.master.d/

总结

NFS 表面上只是把远程目录挂载成本地目录,但真正需要掌握的并不是一条:

1
mount -t nfs ...

而是背后的完整模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Client

│ NFSv3 / NFSv4

Network

│ TCP / RPC

NFS Server


/etc/exports

├── rw / ro
├── sync / async
├── root_squash
└── all_squash


UID / GID


Linux 权限

├── owner
├── group
├── mode
└── ACL


SELinux


真实文件系统

尤其需要记住三个容易踩坑的点。

第一,NFS 的普通身份模型主要依赖:

1
UID/GID

而不是 SSH 用户名和密码。因此多台 Linux 主机使用 NFS 时,统一 UID/GID 非常重要。

第二:

1
/etc/exports 中的 rw

只代表协议层允许写,不代表任何用户都可以修改任意文件。最终文件访问仍然受到 Linux 权限、ACL、UID/GID、squash 和 SELinux 控制。

第三,NFS 自动挂载需要区分三种机制:

1
/etc/fstab

适合固定的开机挂载;

1
fstab + x-systemd.automount

适合固定目录的按需挂载,可以避免启动时 NFS Server 不可用导致的问题;

1
autofs

适合大量动态 NFS 目录,并支持按需挂载和空闲自动卸载。

对于 Rocky Linux 9 环境,推荐的学习路线是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
基础 mount

/etc/exports

rw / ro

UID / GID

root_squash

all_squash

NFSv3 / NFSv4

RPC / TCP 2049

nfsstat

fstab

systemd automount

autofs

SELinux / firewalld

故障排查

完成这些实验以后,就已经不只是“会配置一个 NFS 共享”,而是能够理解 NFS 从网络协议、Linux 身份权限、文件系统挂载、systemd 到自动挂载和故障恢复的一整套工作机制。


Rocky Linux 9 NFS 完整学习笔记:原理、配置、自动挂载与实操实验
https://allendericdalexander.github.io/2026/09/09/devops/learn/rocky-linux-9-nfs-complete-guide/
作者
AtLuoFu
发布于
2026年9月9日
许可协议