简介
NFS(Network File System,网络文件系统)是一种让客户端通过网络访问远程服务器目录的文件系统协议。
它和 scp、rsync 最大的区别是:
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
| cat /mnt/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 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 是文件传输:
文件复制完成后,A 和 B 各自拥有独立副本。
rsync 是同步:
它更适合:
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
| 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 2 3 4
| +3 支持 NFSv3 +4 支持 NFSv4 +4.1 支持 NFSv4.1 +4.2 支持 NFSv4.2
|
客户端挂载时可以指定:
或者:
五、/etc/exports
NFS Server 最重要的配置就是 export。
传统配置文件:
也可以使用:
例如:
1
| /etc/exports.d/lab.exports
|
配置:
1
| /srv/nfs/lab 192.168.0.0/24(rw,sync,root_squash)
|
格式:
拆开来看:
表示要共享的目录。
表示整个:
网段都允许访问。
表示协议层允许读写。
表示写请求同步提交。
表示客户端 root 不会直接成为服务器 root。
注意:
客户端地址和括号之间不要添加空格。
六、常用 exports 参数
rw
允许读写:
ro
只读:
sync
同步写入:
Server 在数据真正提交之后才返回成功。
优点是数据一致性更好。
async
异步:
可能提高性能,但是服务器突然宕机时存在更高的数据丢失风险。
root_squash
默认推荐:
客户端:
不会直接成为 Server:
而会映射为匿名用户。
no_root_squash
意味着客户端 root 可以作为服务器 root 操作共享文件。
除非明确知道自己在做什么,否则不要使用。
all_squash
把所有客户端用户都映射为匿名用户。
可以配合:
例如:
1
| all_squash,anonuid=1000,anongid=1000
|
这在客户端 UID/GID 不一致时很有用。
七、NFS 最关键的权限模型:UID/GID
很多第一次学习 NFS 的人会以为:
实际上普通 NFS sec=sys 主要看的是:
例如 Server:
得到:
1
| uid=1000(rocky) gid=1000(rocky)
|
Mac 客户端可能:
如果 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 并不会自动把它变成:
这就是为什么 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 2 3 4 5 6 7 8 9
| NFS rw/ro ↓ UID/GID ↓ Linux owner/group/other 权限 ↓ ACL ↓ SELinux
|
例如目录:
但是里面有一个文件:
1
| -rw-r--r-- 501 20 mac.txt
|
rocky 用户仍然可能不能修改这个文件。
因为目录权限控制的是:
而文件本身的:
控制文件内容是否可以修改。
九、sudo 与 shell 重定向
一个非常常见的问题:
1
| sudo echo "changed by rocky" >> /srv/nfs/lab/mac.txt
|
可能仍然得到:
原因是:
只有 echo 以 root 执行。
但是:
是当前 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:
正常应该:
不要因为 NFS 权限问题直接:
如果怀疑 SELinux:
1
| sudo ausearch -m AVC -ts recent
|
查看目录 SELinux 标签:
防火墙状态:
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 2
| TARGET SOURCE FSTYPE OPTIONS /mnt/nfs-lab 192.168.0.50:/srv/nfs/lab nfs4 rw,...
|
也可以:
或者:
不过日常排查建议优先:
如果想看某一个挂载:
十二、fstab 自动挂载
Linux 中传统的开机持久挂载配置文件:
例如:
1
| 192.168.0.50:/srv/nfs/lab /mnt/nfs-lab nfs defaults,_netdev,nofail,vers=4.2 0 0
|
其中:
表示这是网络文件系统。
表示 NFS Server 无法访问时,不要让系统因此启动失败。
配置以后先不要急着重启。
执行:
测试配置是否正确。
然后:
确认。
十三、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
|
此时启动过程中并不会立刻访问 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
|
对于:
systemd 单元通常会编码为:
1
| mnt-nfs\x2dlab.automount
|
查看:
1
| systemctl status 'mnt-nfs\x2dlab.automount'
|
真正挂载后还会有:
查看:
1
| systemctl status 'mnt-nfs\x2dlab.mount'
|
十四、autofs
autofs 和 systemd 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
| lab -fstype=nfs,rw,vers=4.2 192.168.0.50:/srv/nfs/lab
|
最终路径:
当第一次执行:
才真正触发 NFS 挂载。
所以:
适合固定挂载。
适合固定目录的按需挂载。
适合大量动态 NFS 目录和自动卸载。
十五、如何判断陌生服务器上的 NFS 是怎么挂载的
先看当前挂载:
然后看 /etc/fstab:
1
| grep -v '^#' /etc/fstab | grep -E 'nfs|nfs4'
|
检查 systemd automount:
1
| systemctl list-units --type=automount
|
检查 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 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 2 3
| sudo mkdir -p /srv/nfs/lab sudo chown rocky:rocky /srv/nfs/lab sudo chmod 777 /srv/nfs/lab
|
这里的:
只用于第一阶段学习,目的是暂时排除 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
|
检查:
实验四:配置 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
| /etc/exports.d/*.exports
|
之后,都可以执行:
重新加载。
实验七:配置防火墙
检查:
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 2
| Export list for localhost: /srv/nfs/lab 192.168.0.0/24
|
查看 RPC:
查看 NFS 版本:
1
| cat /proc/fs/nfsd/versions
|
查看端口:
实验九: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
| echo "linux client" > /mnt/nfs-lab/linux-client.txt
|
检查服务端:
1
| cat /srv/nfs/lab/linux-client.txt
|
实验十:使用 nfsstat
查看挂载参数:
可能看到:
1 2 3 4 5 6
| vers=4.2 rsize=1048576 wsize=1048576 hard proto=tcp sec=sys
|
查看客户端统计:
查看服务端统计:
实验十一: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
| 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
|
查看:
确认:
实验十二:理解 UID/GID
查看 rocky:
例如:
1
| uid=1000(rocky) gid=1000(rocky)
|
创建:
1
| touch /srv/nfs/lab/rocky-user.txt
|
查看数字 UID/GID:
应该能看到:
1
| 1000 1000 rocky-user.txt
|
如果另外一台客户端 UID 是:
通过 NFS 创建文件以后,Server 很可能直接显示:
这说明 NFS 使用的是 UID/GID 身份模型,而不是简单通过用户名匹配。
实验十三:制造 Permission denied
把目录权限恢复得更合理:
1
| sudo chmod 775 /srv/nfs/lab
|
检查:
假设从另一个 UID 不一致的客户端创建:
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
|
会得到:
原因不是 NFS rw 失效,而是:
没有:
文件的写权限。
实验十四:理解 sudo 重定向问题
执行:
1
| sudo echo "changed by rocky" >> /srv/nfs/lab/mac.txt
|
仍然可能:
因为:
由 sudo 运行,而:
还是当前 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。
这就是:
保护机制。
实验十六: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
|
应用:
此时所有客户端用户通过 NFS 创建文件,都映射为:
验证:
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
| cat /mnt/nfs-lab/hello.txt
|
正常。
尝试写:
1
| touch /mnt/nfs-lab/readonly-test.txt
|
应该得到类似:
这里和:
含义不同。
优先检查:
1 2
| NFS export 是否 ro mount 是否 ro
|
而:
优先检查:
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
| 192.168.0.50:/srv/nfs/lab /mnt/nfs-lab nfs defaults,_netdev,nofail,vers=4.2 0 0
|
测试:
检查:
如果没有错误,就说明配置有效。
实验十九: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
|
访问:
然后:
可以看到访问目录后才真正挂载。
具体查看 systemd unit:
1
| systemctl status 'mnt-nfs\x2dlab.automount'
|
以及:
1
| systemctl status 'mnt-nfs\x2dlab.mount'
|
实验二十:配置 autofs
如果前面 /etc/fstab 已经挂载 /mnt/nfs-lab,可以保留它,autofs 使用另外一个目录:
安装:
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
|
查看服务:
访问:
查看:
此时应该可以看到对应 NFS 挂载。
查看 autofs 配置:
查看:
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
|
之后访问恢复。
这是默认:
挂载语义的重要表现。
对于重要数据,一般不要为了避免等待就随意使用:
因为可能把暂时性的网络故障转化为应用层 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 2
| flock -n /mnt/nfs-lab/my.lock \ -c 'echo "I got lock"'
|
即可获得锁。
这个实验说明 NFS 不只是文件读写,还涉及:
实验二十四:查看一台服务器所有 NFS 配置
查看当前实际挂载:
查看 /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:
查看 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
| cat /etc/exports.d/*.exports
|
重新加载:
重点确认客户端 IP 是否在允许范围。
Connection refused
检查:
1
| systemctl status nfs-server
|
端口:
防火墙:
1
| sudo firewall-cmd --list-all
|
Permission denied
检查客户端身份:
检查 Server 文件:
检查整个路径:
检查 exports:
检查 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
客户端:
Server:
重点看是不是:
NFS 卡住
检查网络:
检查 NFS 端口:
1
| nc -vz 192.168.0.50 2049
|
Server:
1
| systemctl status nfs-server
|
如果使用默认 hard mount,Server 暂时不可访问时客户端操作可能等待和重试,这属于 NFS 的正常故障语义之一。
umount 提示 target is busy
先离开目录:
然后:
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 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 的普通身份模型主要依赖:
而不是 SSH 用户名和密码。因此多台 Linux 主机使用 NFS 时,统一 UID/GID 非常重要。
第二:
只代表协议层允许写,不代表任何用户都可以修改任意文件。最终文件访问仍然受到 Linux 权限、ACL、UID/GID、squash 和 SELinux 控制。
第三,NFS 自动挂载需要区分三种机制:
适合固定的开机挂载;
1
| fstab + x-systemd.automount
|
适合固定目录的按需挂载,可以避免启动时 NFS Server 不可用导致的问题;
适合大量动态 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 到自动挂载和故障恢复的一整套工作机制。