需要在多台 Linux 机器之间共享文件时,NFS 是最省事的方案之一:服务端导出一个目录,客户端把它挂载成本地路径,读写就像操作本地磁盘一样。这篇以 Rocky Linux 9 为例,把 NFS 从安装、导出、启动到客户端挂载、跨机读写的完整链路走一遍——服务端和客户端各跑在一个 rockylinux:9 容器里(同一台宿主机上的自定义网段),所有输出都来自这次实跑;文中三个典型报错也是这次故意做错复现出来的。

规划与前置条件

先定好两台机器的角色、目录和 IP,后面的命令都按这张表来:

服务器 角色 目录 IP 地址
Rocky Linux 9 服务端 /export/nfs 192.168.254.2
Rocky Linux 9 客户端 /data 192.168.254.3

动手前确认三件事:两台机器网络互通(能互相 ping 通);有 root 或 sudo 权限;服务端 2049(NFS)和 111(rpcbind)端口没被防火墙拦住。内网环境一般都满足。

注:容器里复现时,导出目录要落在支持 NFS 导出的文件系统上(我用的是 tmpfs),不然 exportfs -r 会报 does not support NFS export;物理机的 xfs/ext4 没有这个问题。

第一步:两端安装 nfs-utils

Rocky 9 上服务端和客户端装的是同一个包,dnf install 会把 rpcbind 作为依赖一起带上:

1
dnf install -y nfs-utils

验证点:执行 rpm -q nfs-utils,应看到 nfs-utils-2.5.4-42.el9 开头的版本号(本次实测 2.5.4-42.el9.aarch64)。

第二步:服务端建目录、写导出规则

创建导出目录并放开写权限:

1
2
mkdir -p /export/nfs
chmod 666 /export/nfs

chmod 666 让所有用户对这个目录可读写,客户端写入时不至于被权限卡住。然后把共享规则写进 /etc/exports,添加这一行:

1
/export/nfs 192.168.254.0/24(rw,no_root_squash,no_all_squash,sync)

这条规则的含义:把 /export/nfs 共享给 192.168.254.0/24 网段,括号里的参数依次是——

  • rw:允许读写
  • no_root_squash:客户端 root 用户保留 root 身份,不降权映射
  • no_all_squash:普通用户保留原有身份,不统一映射成匿名用户
  • sync:写入同步落盘,数据更安全,速度稍慢

注意网段要和客户端实际 IP 对得上:这一行只允许 192.168.254.x 的机器挂载,网段外的客户端会被服务端拒绝(下文失败出口里有实测报错)。改完让配置生效:

1
exportfs -r

验证点:exportfs -r 无任何报错输出;再执行 exportfs -v,应看到 /export/nfs 连同各项参数被列出来。

配图1

第三步:服务端启动服务

NFS 依赖 RPC 体系,rpcbind 和 nfs-server 两个服务都要起,顺序是先 rpcbind:

1
2
systemctl start rpcbind
systemctl start nfs-server

验证点:rpcinfo -p localhost 应列出 nfs(program 100003,2049 端口)和 mountd 的注册行——rpcbind 正常工作时才能看到这张服务表;缺了 rpcbind,这张表是空的,客户端自然连不上。本地再执行 showmount -e localhost,应看到自己的导出清单。

配图2

生产环境设成开机自启,免得重启后共享悄悄失效:

1
systemctl enable rpcbind nfs-server

第四步:客户端查清单、挂载

客户端也装好 nfs-utils 并启动 rpcbind(NFSv3 挂载时本地要跑 rpc.statd 做文件锁,少了它会挂载失败,见失败出口第二条)。然后建好挂载点,先问服务端导出了什么:

1
2
3
systemctl start rpcbind
mkdir /data
showmount -e 192.168.254.2

验证点:showmount -e 应列出 /export/nfs 192.168.254.0/24——能看到清单说明网络和 RPC 链路都通,这一步通了再挂载,能省掉大半排查时间。

配图3

确认看到 /export/nfs 后执行挂载:

1
mount -t nfs 192.168.254.2:/export/nfs /data/

验证点:df -hT /data/ 文件系统一列应显示 nfs,设备列是 192.168.254.2:/export/nfs。

挂载成功后,往 /data 写的文件实际就落在服务端的 /export/nfs 里。跨机读写验证:客户端 echo "hello from client" > /data/write-test.txt,回服务端 cat /export/nfs/write-test.txt,应看到同一行内容——文件确实穿过网络落在了服务端磁盘上。

配图4

历史版本差异(CentOS 7)

老读者手头还是 CentOS 7 的话,整条流程不变,只有三处细节不同:包管理器是 yum(el8 起 dnf 取代 yum,用法兼容);nfs-utils 版本老得多(el7 是 1.3.0,协议默认值略旧,跨版本混挂时建议显式 -o vers=3 或 vers=4);启动命令完全一致,仍是 systemctl start rpcbind nfs-server。原文成文时的环境就是 CentOS 7.6,当时在 7.6 客户端上这套命令同样跑通。

安装后验证与失败出口

整条链路的最终验收就一条:客户端写、服务端读得见。想回退时按逆序拆掉:

1
2
3
4
# 客户端卸载
umount /data/
# 服务端停用
systemctl disable --now nfs-server rpcbind

四个高频报错,都是这次容器实跑里复现过或对着现象处理过的:

  • mount.nfs: access denied by server:客户端 IP 不在导出网段里。实测把导出改成 192.168.0.0/24 再让 192.168.254.3 去挂,稳定复现这个报错。核对 /etc/exports 的网段和客户端实际 IP,改完 exportfs -r 即可,不必重启服务。
  • mount.nfs: rpc.statd is not running:客户端本地 rpcbind/statd 没起来,NFSv3 挂载需要它做锁协商。最小化安装、容器里最容易遇到:systemctl start rpcbind 并确认 rpc.statd 在跑;临时绕过可用 mount -o nolock(代价是没有跨机文件锁)。
  • 挂载成功但写入 Permission denied:导出参数没放开 root 身份。实测把参数退回默认 root_squash 后,客户端 root 写文件立刻报 Permission denied——root 被映射成了 nobody。确认 no_root_squash 是否按需配置,以及目录权限(chmod 666)是否执行。
  • showmount 超时或 clnt_create 失败:服务端 rpcbind 或 nfs-server 没起全,回服务端看 systemctl status 与防火墙 111 端口。

配图5

小结

回看整条链路:装 nfs-utils、写 /etc/exports、起 rpcbind + nfs-server、客户端 showmount 确认后挂载,每一步都有对应的”应看到什么”。几条经验收个尾:no_root_squash 让客户端 root 保留 root 身份,实测关掉它写入立刻被拒,建议只在可信内网开;改 exports 后 exportfs -r 即时生效,不必重启 nfs-server;挂载前先 showmount -e 问一声,能把挂载失败的排查时间砍掉大半。


本文由作者 2020-2024 年间的 CSDN 博客文章重构而来,原发布于 CSDN。