1. 这个章节到底在学什么
RH134进入第九个主题“访问网络附加存储”,名字听着有点学院派,翻译成大白话就是:怎么把一台Linux服务器上的目录,通过网络共享给其他机器用,并且在客户端上像访问本地磁盘一样去读写它。
这个能力在真实生产环境里太常见了。比如你有一台Web服务器集群,后端代码要同步到多台节点上,总不能一台一台scp过去吧,直接在共享存储上放一份,大家挂载同一个目录就行。再比如开发环境里,Windows机器上的代码要跑到Linux虚拟机里去编译,与其来回拷贝,不如在虚拟机里挂载一个共享目录。我在实际项目中见过太多类似需求,这门技术学不好,后面碰壁是迟早的事。
红帽把NFS(Network File System)作为这一章的核心内容,是因为NFS就是Linux世界里最主流的网络附加存储协议之一,工具栈成熟、配置简单、性能足够应付绝大多数场景。这一章在RH134里的定位,不是让你成为存储专家,而是让你具备三件事的能力:
- 第一,能看懂一个NFS共享是怎么暴露出来的,导出目录的权限选项是什么意思。
- 第二,能在客户端上顺利完成挂载、开机自动挂载、按需挂载。
- 第三,能处理挂载失败、权限拒绝、性能异常这几类最常见故障。
这一章的知识会在RHCSA考试里占据几道题的分量,更重要的是,它几乎是你后面学习高可用集群、虚拟化存储、容器持久化存储的基础。Kubernetes里的PV/PVC逻辑、GlusterFS、Ceph的客户端挂载方式,多少都带着NFS的影子。所以这一章千万别只当应试内容看过就算完,值得在实验环境里反复折腾几遍。
适合谁来读这篇文章?正在准备RHCSA/RHCE的人、工作中需要给Linux服务器配置共享存储的运维人员,还有那些刚接触Linux、想搞明白“网络磁盘”到底怎么玩的新手。下面所有内容,我会按照从原理到配置、从服务端到客户端、从常规操作到故障排查的顺序展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先把原理讲透:RPC、rpcbind与NFS协议家族
2.1 NFS不是一个单独的“文件传输协议”
很多刚接触NFS的人会被它的工作方式绕晕。你用浏览器访问网页,走的是HTTP,端口固定是80,请求-响应清清楚楚。但NFS不一样,它在底层依赖一个叫RPC(Remote Procedure Call,远程过程调用)的机制,你可以把RPC理解成“通用消息中间人”——客户端发起一个函数调用请求,中间人帮它路由到服务端对应的处理程序上,再把结果原样传回去。
NFS之所以要这么干,是因为它有多个子服务协同工作。mount协议负责处理挂载请求,nfs协议负责处理文件读写,锁管理、状态监控也各有各的模块。如果每个都固定一个端口,管理和防火墙规则会变成一场噩梦。于是RPC框架里有一个特殊的服务叫rpcbind,它像电话总机一样,记录着“哪个程序在哪个端口上提供服务”。客户端想挂载NFS,先跑到rpcbind上问一句“NFS服务在哪个端口”,拿到具体端口号之后再连接过去。
这也是为什么你在服务端配置文件里能看到sunrpc、mountd这些单词,它们不是NFS本身,而是NFS依赖的RPC子系统组件。这个机制在NFSv3时代特别明显,因为v3版本需要rpcbind配合,端口也不固定。到了NFSv4时代,事情变得简单了一点:v4版本内置了挂载协议、锁协议,而且固定使用TCP 2049端口,理论上不再强依赖rpcbind。但在实际的红帽考试和多数生产环境里,你仍然需要把rpcbind相关的服务启起来,因为系统里其他工具还会依赖它。
2.2 NFS版本怎么选:v3还是v4
Red Hat Enterprise Linux(包括RHEL、CentOS、Rocky这些衍生版)上,内核本身就支持NFS协议,服务端和客户端都不需要安装什么巨型软件包,只需要装几个工具套件。
在配置和挂载的时候,NFS版本是一个绕不开的选择题。v3和v4的主要差异,我整理了一张表:
| 对比项 | NFSv3 | NFSv4 |
|---|---|---|
| 传输协议 | TCP/UDP均可 | 通常只用TCP |
| 固定端口 | 否,依赖rpcbind动态分配 | 是,TCP 2049 |
| 挂载协议 | 独立mount协议,配合rpcbind | 内置,简化交互 |
| 锁管理 | 独立锁服务(NSM) | 内置锁管理 |
| 加密能力 | 无 | 支持Kerberos(krb5p) |
| 性能表现 | 某些场景下吞吐略高 | 通常延迟更稳定,安全性好 |
我的建议是:在RHEL 9、Rocky 9这些较新的系统上,直接使用NFSv4,安全性和稳定性都更好。只有当你需要跟非常老旧的设备、嵌入式系统互通时,才考虑降级到v3。实际配置时,你可以在/etc/nfs.conf里做版本控制,也可以在挂载命令里用-o vers=4强制指定。
2.3 客户端视角的访问流程
理解NFS的客户端访问流程,对后面排查问题帮助非常大。一次最简单的NFS挂载,客户端要做的事大约有这么几步:
- 客户端发起挂载请求,如果域名解析有问题,可能先尝试
portmapper查询。 - 客户端向服务端的rpcbind询问mountd端口。
- 客户端跟mountd通信,提交要挂载的导出目录路径。
- mountd检查导出配置和客户端IP,如果允许,就返回一个文件句柄。
- 客户端拿着文件句柄,向NFS服务端发起实际的I/O请求。
- NFS服务端转交给内核的NFS守护进程,读写本地文件系统。
你会发现,这里面每一步都有可能出现故障。rpcbind没起来、防火墙把端口挡住了、导出配置里没有这个客户端IP、SELinux布尔值没放开……任何一个环节断了,你都挂不上。这也是为什么NFS排障必须一层一层来,不能只看表面错误信息。
3. 服务端配置:真正理解/etc/exports
3.1 环境准备与软件安装
先把实验环境说清楚。我的环境是这样的:一台服务端,系统是Rocky Linux 9,IP地址172.16.140.200,用于共享的目录是/data/shared;一台客户端,系统也是Rocky Linux 9,IP地址172.16.140.150,需要把服务端的共享目录挂载到本地/mnt/nfs。
服务端需要安装的软件包是nfs-utils,在红帽系系统上,这个包同时提供了服务端和客户端工具。命令很简单:
bash复制sudo dnf install -y nfs-utils
装完以后,启动服务并设置开机自启:
bash复制sudo systemctl enable --now nfs-server rpcbind
这里有坑。在旧版本系统上,你可能习惯写nfs或者nfslock,但在RHEL 9和Rocky 9上,服务名统一叫nfs-server。另外,rpcbind服务在nfs-server启动后会自动被依赖拉起,但为了保险起见,我习惯显式地把rpcbind也设成开机自启,防止某些情况下服务顺序问题导致NFS启动异常。
创建共享目录并设置权限:
bash复制sudo mkdir -p /data/shared
sudo chmod 755 /data/shared
如果这个目录要给特定用户或用户组使用,记得把owner和group改到位。很多初学者在这里吃过亏:目录建好了、exports也写对了,但客户端写文件时提示Permission denied,结果一看目录权限是root:root加755,普通用户根本写不进去。
3.2 exports文件语法与常见选项
NFS服务端的核心配置文件是/etc/exports。每一行的格式是:
code复制导出目录 允许访问的主机(选项1,选项2) 允许访问的主机2(选项3)
举个例子:
code复制/data/shared 172.16.140.0/24(rw,sync,no_root_squash)
这行配置的意思是:把/data/shared目录共享给172.16.140.0/24整个网段的机器,权限是读写,数据同步写入磁盘,不把客户端root用户压制成匿名用户。
注意,主机和括号之间不能有空格。这是我每次都会强调的细节,因为/etc/exports对格式极其敏感,但凡多一个空格,格式解析就会出错,导出的目录会变成你完全看不懂的样子。
接下来把常用选项逐一说明。这些选项是考试和实际工作中的重点,值得认真记:
| 选项 | 含义 | 典型用法说明 |
|---|---|---|
| rw | 读写权限 | 客户端可读可写,默认是ro只读 |
| ro | 只读权限 | 客户端只能读取,不能写入 |
| sync | 同步写入 | 服务端确认数据落盘后才响应客户端,安全但稍慢 |
| async | 异步写入 | 服务端先响应再落盘,性能好但有数据丢失风险 |
| root_squash | 把root映射为匿名用户 | 默认选项,防止客户端root在服务端拿到root权限 |
| no_root_squash | 不压制root | 客户端root写文件时,文件属主就是root,用起来方便但危险 |
| all_squash | 所有用户都映射为匿名用户 | 常用于公共共享目录 |
| anonuid | 指定匿名用户UID | 配合all_squash使用,控制匿名用户实际身份 |
| anongid | 指定匿名用户GID | 配合all_squash使用 |
| no_subtree_check | 关闭子树检查 | 提升性能,现代系统默认行为 |
| wdelay | 延迟写入合并 | 默认开启,避免频繁写入时性能偏低 |
关于no_root_squash,我必须多说一句:这个选项在生产环境里要极其谨慎地使用。它意味着客户端上的root用户,在写NFS共享文件时,创建出来的文件属主是root。一旦共享的目录里有恶意脚本或者配置失误,影响范围会被放大。红帽考试里经常考这个点:默认情况下客户端root是否拥有写权限?答案是否定的,因为root会被压制成nobody。
3.3 用exportfs命令管理导出
写完/etc/exports之后,需要让服务端重新读取配置。有两类做法:
bash复制sudo exportfs -r # 重新读取exportfs配置,并同步到内核导出表
sudo exportfs -a # 导出所有在/etc/exports中配置的目录
我推荐用exportfs -r,因为它会把已经不存在的导出项清理掉,让内核中的导出状态和配置文件保持一致。如果你想在不重启服务的情况下临时导出一个目录,可以用:
bash复制sudo exportfs -o rw,sync 172.16.140.150:/data/shared
查看当前导出了哪些目录,用:
bash复制sudo exportfs -v
输出会列出所有导出项及生效的选项。这个命令在排障时非常好用,因为你可以一眼看出配置的选项是否跟预期一致。比如你明明在exports里写了rw,但exportfs -v显示的是ro,那说明你的语法可能有问题,或者没有用-r重载。
3.4 防火墙与SELinux:新手最容易忽略的两个否决项
服务端配置看起来完美,客户端就是连不上,挂载时一直卡住,然后提示超时,十有八九是防火墙或者SELinux在捣乱。
在RHEL 9和Rocky 9上,firewalld默认是开着的。你需要放行NFS相关的服务:
bash复制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
这里要说明的是,这三条命令分别放行了NFS的2049端口、mountd端口和rpcbind端口。在NFSv4之前,mountd和rpcbind的端口是动态的,所以一定要通过服务名放行,而不是写死端口号。如果只放行了nfs而漏了mountd,客户端挂载时会在“正在挂载”状态卡很久,最后报超时错误。
再看SELinux。红帽系统上SELinux默认是Enforcing状态,NFS相关的布尔值如果没有打开,服务端即使配置正确也无法提供正常服务。核心的两个布尔值:
bash复制sudo setsebool -P nfs_export_all_rw 1
sudo setsebool -P nfs_export_all_ro 1
这两个布尔值允许NFS导出目录时不管目录原有的SELinux类型,正常提供读写或只读服务。如果不打开,客户端挂载后可能连目录列表都看不到,或者写文件时提示权限错误,而去查服务端审计日志,会看到一堆avc: denied的记录。
我平时排障的标准动作是:发现NFS有问题,先看SELinux布尔值,再看firewalld规则,最后才回到exports配置上。因为配置错误往往报错信息很明确,而防火墙和SELinux的错误信息容易伪装成“超时”或“权限不足”,极具迷惑性。
4. 客户端访问:从手工挂载到开机自动挂载
4.1 showmount与mount:最基础的客户端工具
客户端这边同样需要安装nfs-utils:
bash复制sudo dnf install -y nfs-utils
首先可以用showmount查看服务端导出了哪些目录:
bash复制showmount -e 172.16.140.200
输出效果大致是这样:
code复制Export list for 172.16.140.200:
/data/shared 172.16.140.0/24
这个命令在排查时很有用,它能在你真正挂载之前就告诉你服务端的导出配置对不对。如果showmount能列出目录,但挂载失败,说明问题出在客户端或者网络层面;如果showmount直接报错,说明服务端导出配置或防火墙/网络有问题。
手工挂载的命令是:
bash复制sudo mount -t nfs 172.16.140.200:/data/shared /mnt/nfs
注意mount后面的写法:服务端IP加冒号加导出目录路径,冒号两边不能有空格。/mnt/nfs这个本地目录必须提前存在且为空,否则挂载后原有文件会被遮住,卸载后才能看到。这一点也经常有人踩坑。
挂载完成后,用df -h查看,会看到类似这样的输出:
code复制172.16.140.200:/data/shared 100G 20G 80G 20% /mnt/nfs
看到这一行,说明挂载成功了。你可以直接往/mnt/nfs里读写文件,就像操作本地目录一样。
4.2 开机自动挂载:fstab与_netdev的配合
手工挂载只对当前会话有效,重启之后挂载关系就消失了。要实现开机自动挂载,需要写/etc/fstab文件。
先给一个重要提醒:NFS挂载写入fstab时,一定要加_netdev选项。这个选项告诉系统,等网络就绪后再挂载,而不是在启动早期就尝试挂载一个依赖网络的设备。如果不加_netdev,系统启动时可能因为网络还没准备好而挂载失败,严重时甚至会导致开机卡住、进入紧急模式。
标准的fstab写法:
code复制172.16.140.200:/data/shared /mnt/nfs nfs defaults,_netdev 0 0
我见过很多人在fstab里写auto或者直接省略选项,结果重启后开不了机。所以这里再强调一次:_netdev是必须的,不是可选项。另一个可选但推荐的选项是nofail,它表示即使挂载失败也继续启动过程,不会卡住系统:
code复制172.16.140.200:/data/shared /mnt/nfs nfs defaults,_netdev,nofail 0 0
写完fstab后,可以用mount -a测试整个fstab是否能被正确解析和挂载:
bash复制sudo mount -a
如果没有报错,再用df -h确认挂载结果。这一步一定要在重启之前做,否则你只能在系统紧急模式里挣扎了。
4.3 autofs:按需挂载的正确姿势
fstab里的自动挂载,解决的是“开机就要挂载”的需求。但实际场景中,很多共享目录并不是时刻都在使用,挂在那边不仅浪费资源,还可能因为网络波动导致大量报错。这时候就用得上autofs——按需挂载服务。
autofs的工作原理很简单:配置一个监控目录,比如/mnt/nfs或者/mnt,当用户访问这个目录下的子目录时,autofs服务会自动执行挂载动作;当一段时间没人访问时,自动卸载。你不需要手动干预,系统会帮你打理好一切。
安装和启动autofs:
bash复制sudo dnf install -y autofs
sudo systemctl enable --now autofs
然后配置主配置文件/etc/auto.master,加入一行:
code复制/mnt /etc/auto.nfs
这行配置的意思是:监控/mnt目录,具体的挂载规则写在/etc/auto.nfs这个文件里。接着创建/etc/auto.nfs,内容如下:
code复制shared -rw,sync 172.16.140.200:/data/shared
这里的shared是访问时的子目录名,也就是说,当你去访问/mnt/shared时,autofs会自动把服务端的/data/shared挂载上来。不需要的时候,它会在空闲超时后自动卸载。
改完配置文件后,重启autofs:
bash复制sudo systemctl restart autofs
然后试试看:
bash复制ls -l /mnt/shared
第一次访问的时候会有一点点延迟,因为autofs在触发挂载,之后就跟本地目录一样流畅。
autofs相比fstab的优势非常明显:不用在开机关机时处理网络依赖,挂载是懒加载的,更稳定;不用的共享不会长期占用资源;可以在同一个监控目录下配置多个共享。
我自己的习惯是:频繁使用且系统关键路径的共享,用fstab加_netdev;偶尔使用或者多台机器共用的共享,用autofs。这个选择不绝对,但能省去很多维护上的麻烦。
4.4 用户与权限:理解root_squash的连锁反应
接下来是很关键的一段。NFS默认的权限模型:客户端上root用户访问NFS共享目录时,服务端会把root映射成一个匿名用户,通常是nobody。这么做的原因很直接:防止客户端root用户直接以root身份写服务端文件,篡改系统文件或者覆盖重要数据。
实际体验是什么样呢?你在客户端用root执行:
bash复制touch /mnt/nfs/testfile
然后回服务端看,会发现这个文件的所有者不是root,而是nobody。这在很多场景下会让人费解:我明明用的是root,怎么文件属主变成了nobody?
如果是普通用户,情况又不一样。客户端上UID为1000的用户,在服务端也对应UID 1000的用户,文件创建出来的属主就是UID 1000。NFS的权限校验是基于UID/GID的,不关心用户名。这就要求服务端和客户端的用户UID体系尽量保持一致,否则就会出现“在客户端看到的用户名和服务端不一致”的诡异问题。
解决方案一般有几种:
- 用
no_root_squash让root不再被压制,但仅限可信网络环境。 - 用
all_squash加anonuid、anongid把所有用户映射到指定账号,比如nfsuser,适合做公共共享目录。 - 用LDAP或NIS集中管理用户,让整个网络内UID一致。
我个人的建议:如果只是学习实验,no_root_squash可以开着,方便调试;但生产环境里,必须严格评估风险,尽量保持默认的squash行为,或者用集中化账号管理体系。
5. 性能与特殊场景:不止是“能挂上”而已
5.1 挂载参数优化:rsize/wsize/hard/soft
NFS挂载时的参数选择对性能和稳定性影响很大。虽然现在NFSv4的默认参数已经比较合理,但在特定业务场景下,手动调整仍然有意义。
常用参数说明:
| 参数 | 作用 | 建议值 |
|---|---|---|
| rsize | 读操作的数据块大小 | 1048576(1MB) |
| wsize | 写操作的数据块大小 | 1048576(1MB) |
| hard | 硬挂载,服务端无响应时一直重试 | 默认,数据安全 |
| soft | 软挂载,服务端无响应时返回错误 | 适合测试环境 |
| timeo | 等待超时时间,十分之一秒为单位 | 600(60秒) |
| retrans | 超时后重试次数 | 默认值即可 |
| intr | 允许中断挂载等待 | 老系统上有用,新版本默认允许 |
| noexec | 禁止在挂载目录中执行二进制文件 | 安全加固时使用 |
| nosuid | 禁止setuid位生效 | 安全加固时使用 |
举例:
bash复制sudo mount -t nfs -o rw,sync,rsize=1048576,wsize=1048576,hard,timeo=600 172.16.140.200:/data/shared /mnt/nfs
这里面hard和soft的选择值得展开讲。hard模式下,如果服务端挂了,客户端的NFS操作会一直阻塞重试,好处是数据不容易丢,坏处是进程可能卡死,表现为无法卸载、无法响应。soft模式下,操作会在超时后失败,给进程返回错误信息,但可能会造成数据不完整。
生产环境里,数据库、应用数据这类对一致性要求极高的场景,建议用hard;普通文件共享、网络不稳定但能容忍偶发失败的环境,soft可能体验更好。我的实践是:正常情况下用hard,但要配好timeo参数,让超时时间合理,并且给NFS单独走稳定网络。
5.2 WSL环境搭建NFS服务端
现在很多人在Windows上使用WSL(Windows Subsystem for Linux)做开发,里面跑的是Linux发行版。有同学问,WSL里能不能创建NFS服务器?答案是可以,但有个前提:WSL2的默认网络模式是NAT,外面要访问WSL里的服务,需要端口转发。而NFS涉及多个端口,转发配置比较繁琐。
最简单的做法是把WSL切换到镜像网络模式。在Windows 11 22H2及以上版本,可以在C:\Users\你的用户名\.wslconfig文件里写入:
code复制[wsl2]
networkingMode=mirrored
然后重启WSL。镜像网络模式下,WSL和Windows共享网络接口,外部机器可以直接访问WSL里监听的端口,NFS这类多端口服务就能正常工作。
接下来在WSL里安装并配置NFS服务端:
bash复制sudo apt update
sudo apt install -y nfs-kernel-server
sudo mkdir -p /data/shared
sudo chmod 777 /data/shared
echo "/data/shared *(rw,sync,no_root_squash,no_subtree_check)" | sudo tee -a /etc/exports
sudo exportfs -r
sudo systemctl restart nfs-kernel-server 2>/dev/null || sudo service nfs-kernel-server restart
注意,WSL里通常没有systemd,至少默认是没有的。所以启动服务要用service命令而不是systemctl。另外WSL的防火墙规则由Windows管理,需要在Windows防火墙里放行WSL进程的入站连接,这一步容易被忽略。
还有一种更省事的办法:不用NFS服务端,直接在Windows里把目录共享出来,然后在WSL里用mount -t drvfs挂载。比如:
bash复制sudo mount -t drvfs '\\server\share' /mnt/share
这种方式虽然叫drvfs,不是NFS,但对开发场景来说往往更实用。如果你只是想在WSL里读写Windows共享目录,这个方法比搭建NFS服务端简单得多。
5.3 银河麒麟V10离线环境NFS配置
银河麒麟V10是国内信创环境中常见的Linux发行版,基于RHEL系改造,所以很多命令和配置方式跟CentOS/RHEL高度相似。在离线环境下安装NFS组件,需要准备离线软件包。
先说结论:离线安装最稳妥的方式是在同版本、同架构的一台联网机器上用dnf download下载RPM包,然后拷贝到目标机器上用rpm -ivh安装。
假设你需要在x86_64架构的银河麒麟V10上安装nfs-utils,可以在联网的机器上执行:
bash复制dnf download nfs-utils --resolve --alldeps --destdir=/tmp/nfs_packages
--resolve会把它依赖的所有包也一起下载下来,--alldeps确保所有依赖都包含在内,--destdir指定下载目录。然后把/tmp/nfs_packages拷贝到离线机器上:
bash复制cd /tmp/nfs_packages
sudo rpm -ivh *.rpm
rpm -ivh *.rpm会把目录下的所有RPM包按照依赖关系自动安装,通常能搞定。
安装完以后,其余配置就跟标准RHEL系系统一样了:编辑/etc/exports、启动nfs-server、设置防火墙放行或直接关闭防火墙(在内网可信环境)。需要提醒的是,银河麒麟的系统服务名可能跟标准RHEL略有差异,如果systemctl status nfs-server显示服务不存在,可以用systemctl list-unit-files | grep nfs找出系统里实际的服务名。
6. 常见故障与排查实录
6.1 经典错误:nfs: server xx not responding, timed out
这大概是NFS排障中遇到最多的错误提示。客户端挂载成功后,一段时间没访问,然后再操作时终端卡住,最后出现类似:
code复制nfs: server 172.16.140.200 not responding, timed out
nfs: server 172.16.140.200 not responding, timed out
nfs: server 172.16.140.200 OK
这个报错的字面意思是:客户端向服务端发出请求后,在规定时间内没有等到响应,重试多次后判定超时。然后当网络恢复时,又输出OK表示恢复。
排障要按照下面这个顺序来:
第一步,ping服务端IP。如果ping不通,那就是网络问题,检查链路、IP配置、交换机端口。如果通,继续第二步。
第二步,确认服务端NFS服务状态。在服务端执行:
bash复制sudo systemctl status nfs-server
如果服务没起来,启动它。如果服务正常,用exportfs -v确认导出目录仍然存在。
第三步,检查防火墙。在服务端检查firewalld状态和规则。很多超时问题的根源是防火墙把某些端口拦了,客户端发出的请求在服务端被丢弃,相当于石沉大海。
第四步,在客户端执行showmount -e 服务端IP,如果这条命令能正常返回导出列表,说明RPC通道是通的,问题可能出在NFS数据连接上;如果这条命令也超时或报错,说明RPC层面就有问题。
第五步,检查服务端负载。如果服务端负载很高,磁盘繁忙,NFS响应会变得极慢,客户端的超时阈值可能不够。可以临时调大timeo参数试试:
bash复制sudo mount -o remount,timeo=600 /mnt/nfs
从我实际遇到的案例来看,这个错误最常见的原因是防火墙把mountd或rpcbind端口挡了,其次是服务端的NFS服务因为SELinux拒绝访问而无法正常响应,第三个常见原因是服务端磁盘容量满了,文件系统变成只读,导致写请求一直失败。
6.2 Permission denied:夹在权限和SELinux之间的谜案
挂载成功了,能看目录列表了,但一写文件就报Permission denied,这个现象也很典型。
最常见的三种原因:
第一种,目录本身没有写权限。/data/shared如果属主是root且权限是755,普通用户当然写不进去。解决方法是修改服务端目录权限或属主:
bash复制sudo chown nobody:nobody /data/shared
sudo chmod 777 /data/shared
第二种,NFS的squash机制把客户端的权限压低了。你在客户端是root,但服务端把root映射成nobody,nobody对目录没有写权限,所以Permission denied。可以在exports里临时改用no_root_squash验证,但生产环境别这么设。
第三种,SELinux在背后拦截。在服务端查看SELinux审计日志:
bash复制sudo tail -f /var/log/audit/audit.log | grep denied
如果看到类型为avc的拒绝记录,跟nfs相关,就用之前提到的setsebool命令把布尔值打开,或者用ausearch配合audit2why查看详细原因。
我在实际工作中遇到过一个非常隐蔽的情况:导出的目录在一个挂载点下面,而这个挂载点本身是用noexec挂载的,导致NFS写文件成功但执行时报权限错误,排查半天才找到真正原因。这类问题没法靠命令速查解决,只能一点点剥离变量。
6.3 重启后挂载丢失或开机卡住
fstab配置了NFS自动挂载,重启以后发现挂载没生效,或者系统卡在启动界面进不了系统。这是fstab相关的典型问题。
原因几乎可以锁定在两点:
一是fstab里没写_netdev,系统在网络就绪前就去挂载NFS,网络不通导致挂载失败,严重时系统会跳过或进入紧急模式。修改fstab:
code复制172.16.140.200:/data/shared /mnt/nfs nfs defaults,_netdev,nofail 0 0
加了nofail之后,即使挂载失败,系统也能正常启动。
二是fstab的格式或字段写错了。NFS行有6个字段,分别是设备、挂载点、文件系统类型、选项、dump备份标记、fsck检查顺序。NFS的dump和fsck标记一般写0 0,如果误写为1 1,系统会在启动时尝试检查NFS文件系统,导致长时间卡住。
如果在开机过程中已经卡住了,可以在系统启动菜单里进入emergency模式,然后注释掉fstab里对应的行,修复后再重启。
6.4 故障排查速查表
| 现象 | 可能原因 | 排查命令/动作 |
|---|---|---|
| showmount -e 超时 | 服务端firewalld拦了mountd/rpc-bind | firewall-cmd --list-all |
| showmount -e 能列目录,mount超时 | NFS服务异常或SELinux拦截 | systemctl status nfs-server、tail audit.log |
| 挂载成功,读文件正常写失败 | 目录权限不足或squash压制 | ls -ld /data/shared、exportfs -v |
| mount -a 报错 | 服务端不开机或网络未就绪 | 检查fstab里的_netdev |
| 客户端写文件很慢 | 服务端磁盘慢或async未开启 | iostat -x 1、检查exportfs选项 |
| 客户端卸载时提示device is busy | 有进程在使用挂载目录 | lsof +f -- /mnt/nfs、fuser -km /mnt/nfs |
最后再分享一个实用技巧:查看客户端当前NFS挂载的详细状态,可以用:
bash复制nfsstat -m
这个命令会显示当前挂载使用的协议版本、传输方式、各项参数,比mount命令的默认输出完整得多。排障时先跑一下,很多东西就一目了然了。
RH134这一章学完,你应该在实验环境里亲自操作一遍完整的流程:在服务端配置exports,在客户端手工挂载、fstab自动挂载、autofs按需挂载,再去故意制造几个故障练练排障。这套流程走下来,NFS这块就稳稳地拿下了。后面学习中遇到高可用、虚拟化存储,回头再看这一章的内容,你会感激自己当初没有偷懒跳过。
