NFS 与 autofs 自动挂载

本文合并自:01-NFS与DHCP服务器.md、03-网络基础.md、1-7-Linux网络配置与故障排查.md

适用环境:RHEL 5 / RHEL 6 / CentOS 6 / CentOS 7 及同系发行版。文中凡是 CentOS 6(含 RHEL 5)与 CentOS 7 命令不同之处,均并列给出并标注版本。

内容覆盖:NFS 概述与选型对比、NFS 与 RPC/rpcbind 的关系、nfs-utils 安装、服务端 /etc/exports 配置与全部导出选项、exportfs 不重启生效、服务启动与端口固定、防火墙放行、客户端 showmount / mount / fstab 持久化、权限与用户映射、autofs 按需自动挂载(主映射与子映射、直接映射、间接映射、通配符映射、超时卸载、NFS 与光盘实例)、排错清单与课堂练习。

范围说明:DHCP 服务见 09-01-DHCP服务.md;网络基础概念与网卡配置见 07-01-网络基础与网络配置.md,本文不再重复。


一、NFS 概述与适用场景

1.1 什么是 NFS

NFS(Network File System,网络文件系统)是一种集群式文件系统,区别于 FAT32、NTFS、ext2/ext3/ext4 等单机文件系统,主要用于 Linux 与 Linux 之间的文件共享。

作用:将一台服务器上的某个目录共享出去,让其他机器可以像使用本地磁盘一样挂载使用。挂载完成后,客户端对该目录的读写、创建、删除等操作与操作本地目录完全一致。

典型使用场景:

  • 多台 Web 服务器共享同一份静态资源、上传附件目录,保证内容一致。
  • 集中式的软件仓库(yum 源)、安装镜像、备份目录共享给内网各节点。
  • 集群节点共享配置文件、日志收集目录。
  • 无盘工作站、PXE 网络安装的根目录或安装源。

1.2 与 FTP、Samba 的对比

对比项 NFS FTP Samba(CIFS/SMB)
主要用途 Linux ↔ Linux 之间的文件系统级共享 文件上传/下载 Windows ↔ Linux 之间的文件与打印共享
访问方式 mount 挂载到本地目录,像本地磁盘一样直接读写 客户端登录后 get / put 传输整个文件 Windows 映射网络驱动器;Linux 用 mount -t cifs
是否支持就地编辑 支持,可直接在挂载点上编辑、追加 不支持,需下载→修改→再上传 支持
认证方式 基于 IP / 主机名 + UID/GID 映射,本身无用户密码认证 用户名 + 密码 用户名 + 密码(可对接 AD 域)
依赖服务 依赖 rpcbind(RPC 端口映射) 独立服务(21 端口) 独立服务(139/445 端口)
跨平台能力 Windows 支持较弱(需另装 NFS 客户端) 全平台通用 全平台通用,Windows 原生支持
性能 局域网内性能好,适合频繁小文件读写 适合大文件整体传输 局域网内性能好,协议开销略大
典型选型建议 内网 Linux 服务器之间共享目录 对外提供文件下载点 办公环境中与 Windows 客户端共享

选型结论:内网、纯 Linux 环境、需要挂载后直接读写 → 选 NFS;需要与 Windows 客户端互通 → 选 Samba;只是对外提供文件下载/上传 → 选 FTP。

1.3 查看当前挂载情况

配置前后都建议确认本机的挂载状态:

mount
# 或
df -h

二、NFS 与 RPC 的关系

2.1 为什么 NFS 必须配合 rpcbind

NFS 服务本身启动了多个后台守护进程(负责挂载请求、文件锁、配额等),这些进程使用的端口大部分不是固定的,而是启动时随机选取。客户端无法预先知道它们在哪个端口上,因此需要一个"总机"来问路。

这个"总机"就是 RPC(Remote Procedure Call,远程过程调用)端口映射服务:

  • NFS 的各个守护进程启动后,会把"我提供什么服务、监听在哪个端口"注册到 RPC 服务中。
  • 客户端先访问 RPC 服务的固定端口 111,询问 NFS 各项服务的实际端口号。
  • 拿到端口后,客户端再直接与对应的 NFS 进程通信。

结论:rpcbind 必须先于 nfs 启动;rpcbind 没起来,NFS 无法对外提供服务,客户端 showmount / mount 都会失败。

2.2 版本差异:portmap 与 rpcbind

系统版本 RPC 端口映射服务名 软件包名
RHEL 5 / CentOS 5 portmap portmap
RHEL 6 / CentOS 6 rpcbind rpcbind
RHEL 7 / CentOS 7 rpcbind(rpcbind.service,且带 socket 激活) rpcbind

RHEL 5 中该服务称为 portmap,RHEL 6 起改名为 rpcbind,作用相同:向客户端通告 NFS 实际使用的端口号。

2.3 rpcinfo 查看 RPC 注册信息

rpcinfo 用于查看 RPC 服务注册情况,是排查 NFS 端口、协议是否正常监听的常用工具。

# 查看本机所有已注册的 RPC 服务
rpcinfo -p localhost

# 查看指定主机的 RPC 注册信息(在客户端排查服务端时很有用)
rpcinfo -p 10.0.0.2

常见 NFS 相关进程:rpc.mountd、nfsd、rpc.rquotad、rpc.statd、rpc.idmapd 等。

若 rpcinfo -p 输出中没有 NFS 相关条目,通常是 nfs 或 rpcbind 服务未正常启动。


三、安装 nfs-utils

3.1 必要软件包

软件包 作用
nfs-utils NFS 服务端与客户端工具(exportfs、showmount、rpc.mountd、rpc.nfsd 等)
nfs-utils-lib NFS 工具库(RHEL 5/6 中为独立包)
rpcbind(RHEL 5 为 portmap) RPC 端口映射,负责通告 NFS 端口

服务端和客户端装的是同一个包 nfs-utils:客户端要用它提供的 showmount 和 NFS 挂载支持;服务端还要用它提供的 exportfs 和守护进程。

3.2 查询是否已安装

rpm -qa nfs* && rpm -qa portmap

输出示例:

nfs-utils-lib-1.0.8-7.6.el5
nfs-utils-1.0.9-42.el5
portmap-4.0-65.2.2.1

3.3 安装

如果查询结果为空,使用 yum 安装。

RHEL 5 / CentOS 5:

yum install portmap -y
yum install nfs* -y

CentOS 6 / CentOS 7:

sudo yum -y install nfs-utils
# rpcbind 通常作为依赖被自动安装,也可显式安装
sudo yum -y install rpcbind

四、服务端配置 /etc/exports

4.1 主配置文件与配置格式

NFS 的导出配置文件是 /etc/exports:

vim /etc/exports

配置格式:

共享目录   客户端1(选项1,选项2,...)  [客户端2(选项...) ...]

书写规则(三条容易出错的细节):

  1. 共享目录必须顶格写,行首不能有空格或制表符。
  2. 客户端与紧跟其后的括号之间不能有空格。/test 10.0.0.11(rw) 是"10.0.0.11 可读写";写成 /test 10.0.0.11 (rw) 则变成"10.0.0.11 使用默认选项"外加"所有主机可读写",是严重的安全事故。
  3. 同一行可以为多个不同客户端指定不同权限,用空格分隔。

4.2 常见配置示例

# 所有 IP 都可以只读挂载
/test    *(ro)

# 仅 10.0.0.0/24 网段可以只读挂载
/test    10.0.0.0/24(ro)

# 10.0.0.11 只读,10.0.0.12 可读写
/test    10.0.0.11(ro)  10.0.0.12(rw)
# 对所有客户端只读,单独放开一台主机读写
/soul *(ro)
/soul 192.168.0.182(rw)
# 只指定客户端地址(只读)
/soul 192.168.0.182(ro)
# 生产中常用的写法:指定网段、可读写、同步写入、压缩所有用户为指定 UID/GID
/data    192.168.0.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000)

4.3 客户端(访问控制)的写法

客户端写法 含义
* 所有主机
10.0.0.0/24 指定网段内的所有主机(CIDR 写法)
10.0.0.0/255.255.255.0 指定网段(掩码写法,等价于上一行)
10.0.0.11 指定单个 IP
nfs.example.com 指定主机名(需要能被解析,依赖 DNS 或 /etc/hosts)
*.example.com 指定域下的所有主机

常见错误:想放开一个网段却只写了网络号而漏掉掩码/前缀,例如写成 /soul 192.168.0.0(rw)。这被解释为"IP 为 192.168.0.0 的这一台主机",结果整个网段都挂不上。指定网段必须带 /24 或 /255.255.255.0。

4.4 导出选项全表

权限与写入方式:

选项 含义
ro 只读挂载(默认值)
rw 可读可写
sync 同步写入:数据写入磁盘后才返回,数据安全但性能略低(推荐)
async 异步写入:先写内存再回写磁盘,性能高但异常断电可能丢数据
wdelay 延迟写入,将多个小写请求合并后再落盘以提升性能(默认)
no_wdelay 不延迟写入,通常与 sync 搭配使用

用户身份映射(squash 系列):

选项 含义
root_squash 将客户端 root(UID 0)的请求映射为匿名用户(默认启用,安全)
no_root_squash 不映射客户端 root,客户端 root 在共享目录中拥有真正的 root 权限(危险,仅特殊场景如无盘系统使用)
all_squash 将所有客户端用户的 UID/GID 请求都映射为匿名用户/组(匿名 UID/GID 通常为 65534,即 nfsnobody/nobody)
no_all_squash 与 all_squash 相反,保留客户端原始 UID/GID(默认启用)
anonuid=UID 自定义匿名用户映射到的 UID
anongid=GID 自定义匿名组映射到的 GID

其他常用选项(补充):

选项 含义
secure 要求客户端请求来自小于 1024 的特权端口(默认)
insecure 允许客户端从大于 1024 的端口发起请求
subtree_check 检查请求的文件是否确实位于导出的子树内
no_subtree_check 不做子树检查,性能更好,是较新版本的默认值

更多写法可通过 man exports 查看。


五、exportfs 命令与不重启生效

修改 /etc/exports 后不必重启 NFS 服务(重启会中断已有客户端的访问),使用 exportfs 直接重载即可:

# 重新加载配置:-a 全部导出,-r 重新导出,-v 显示详细信息
sudo exportfs -arv

# 查看本机当前实际导出的共享(含生效的全部选项,包括默认值)
exportfs -v

exportfs 常用选项:

选项 作用
-a 全部导出(或配合 -u 全部取消导出)
-r 重新导出 /etc/exports 中的所有目录,并同步 /var/lib/nfs/etab
-u 取消一个或多个已导出的目录
-v 显示详细操作信息
-o 临时指定导出选项,不写入配置文件

常用组合:

# 重载全部配置(最常用)
exportfs -arv

# 取消全部导出
exportfs -auv

# 临时导出一个目录(不写 /etc/exports,重启后失效)
exportfs -o rw,sync 192.168.0.0/24:/tmp/share

# 取消单个导出
exportfs -u 192.168.0.0/24:/tmp/share

exportfs -v 与 /var/lib/nfs/etab 显示的是真正生效的配置。排错时应对比 /etc/exports(你写的)与 exportfs -v(实际生效的),若不一致说明忘了执行 exportfs -arv。


六、启动服务、端口与防火墙

6.1 启动服务并设置开机自启

注意启动顺序:先 rpcbind,再 nfs。

RHEL 5 / RHEL 6 / CentOS 6(SysV init 方式):

# RHEL 5 中 rpcbind 名为 portmap
/etc/init.d/rpcbind start       # 负责通知客户端 NFS 的端口号
/etc/init.d/nfs start

# 等价的 service 写法
service rpcbind restart
service nfs restart

# 设置开机自启
chkconfig rpcbind on
chkconfig nfs on

# 查看状态
service nfs status

CentOS 7 / RHEL 7(systemd 方式):

sudo systemctl restart rpcbind.service
sudo systemctl restart nfs.service

# 服务端的真实单元名是 nfs-server.service(nfs.service 是它的别名)
sudo systemctl restart nfs-server.service

# 开机自启(enable --now 可同时启动)
sudo systemctl enable --now rpcbind
sudo systemctl enable --now nfs-server

# 查看状态
sudo systemctl status nfs-server

版本差异对照表:

操作 CentOS 6 / RHEL 6(及 RHEL 5) CentOS 7 / RHEL 7
RPC 服务名 rpcbind(RHEL 5 为 portmap) rpcbind.service
NFS 服务端服务名 nfs nfs-server.service(别名 nfs.service)
启动 service nfs start / /etc/init.d/nfs start systemctl start nfs-server
重启 service nfs restart systemctl restart nfs-server
查看状态 service nfs status systemctl status nfs-server
开机自启 chkconfig nfs on systemctl enable nfs-server
端口固定配置文件 /etc/sysconfig/nfs /etc/sysconfig/nfs(CentOS 8+ 改为 /etc/nfs.conf)
默认防火墙 iptables firewalld

CentOS 7 上 rpcbind 带 socket 激活(rpcbind.socket),有时无需显式启动也会被拉起;但生产环境仍建议显式 enable 以保证开机顺序正确。

6.2 NFS 使用的端口与端口固定

NFS 的端口分两类:

服务 端口 是否固定
rpcbind 111(tcp + udp) 固定
nfsd(NFS 主服务) 2049(tcp + udp) 固定
rpc.mountd、rpc.statd、rpc.rquotad、lockd 等辅助服务 随机 不固定(每次启动都可能变)

正因为辅助服务端口随机,无法编写固定的防火墙规则。需要通过防火墙限制访问时,必须先把这些端口固定下来。编辑 /etc/sysconfig/nfs,确保有以下行:

RQUOTAD_PORT=875
LOCKD_TCPPORT=32803
LOCKD_UDPPORT=32769
MOUNTD_PORT=892
STATD_PORT=662
STATD_OUTGOING_PORT=2020
RDMA_PORT=20049

重启服务使端口固定生效:

CentOS 6:

service rpcbind restart
service nfs restart

CentOS 7:

sudo systemctl restart rpcbind
sudo systemctl restart nfs

固定完成后用 rpcinfo -p localhost 确认端口是否已按配置生效。

6.3 防火墙放行

课堂环境的临时做法:

iptables -F                  # 临时清空规则
chkconfig iptables off       # 关闭开机自启(CentOS 6)
# 或使用 setup 图形工具,将 firewall 前的 * 去掉并保存

CentOS 7 上还要注意:

# CentOS 7 默认防火墙是 firewalld,iptables -F 不影响 firewalld 管理的规则
sudo systemctl stop firewalld

# 仅清空原生 iptables 规则时使用
sudo iptables -F

CentOS 7 的坑:默认防火墙为 firewalld,iptables -F 仅清空 iptables 规则,不会影响 firewalld 管理的规则。挂载不上时如果只做了 iptables -F 就以为防火墙已放开,会白排查很久。正确做法是 systemctl stop firewalld,或用 firewall-cmd 精确放行。

生产环境应精确放行(iptables 批量脚本):

grep -oP '^[A-Z_]+_PORT=\K\d+' /etc/sysconfig/nfs | while read port; do
    [ -n "$port" ] || continue
    iptables -I INPUT -p tcp --dport $port -j ACCEPT
    iptables -I INPUT -p udp --dport $port -j ACCEPT
done

必须只取 KEY=数字 形式的行。早期写法 grep -v ^# /etc/sysconfig/nfs | awk -F= '{print $2}' | while read port; do ... 会把空行与非 KEY=VALUE 行也取出来,产生空字符串,使 iptables --dport 报参数错误。因此这里用 grep -oP 精确提取,并保留 [ -n "$port" ] || continue 作为兜底。

早期写法作为对照(不推荐,仅供理解历史讲义):

grep -v ^# /etc/sysconfig/nfs |
awk -F= '{print $2}' |
while read port
do
    iptables -I INPUT -p tcp --dport $port -j ACCEPT
    iptables -I INPUT -p udp --dport $port -j ACCEPT
done

永久生效:把以上规则写入防火墙配置文件 /etc/sysconfig/iptables(CentOS 6 亦可用 service iptables save)。

除固定端口外,还必须放行两个主端口:

# rpcbind 的 111 与 nfsd 的 2049
iptables -I INPUT -p tcp --dport 111 -j ACCEPT
iptables -I INPUT -p udp --dport 111 -j ACCEPT
iptables -I INPUT -p tcp --dport 2049 -j ACCEPT
iptables -I INPUT -p udp --dport 2049 -j ACCEPT

CentOS 7 firewalld 的等价做法(推荐):

# 按服务放行,firewalld 已内置 nfs / mountd / rpc-bind 服务定义
sudo firewall-cmd --permanent --add-service={nfs,mountd,rpc-bind}
sudo firewall-cmd --reload

# 或按端口放行
sudo firewall-cmd --add-port=2049/tcp --permanent
sudo firewall-cmd --reload

# 确认放行结果
sudo firewall-cmd --list-all

七、客户端挂载

7.1 查看服务端共享列表(showmount)

# 列出服务端导出的共享目录(最常用的连通性验证手段)
showmount -e 10.0.0.2
showmount -e 192.168.0.183

# 查看服务端已被客户端挂载的目录
showmount -d 10.0.0.2

# 查看所有客户端及其挂载的目录
showmount -a 10.0.0.2

输出示例(能显示共享目录即代表服务端 NFS 与 rpcbind 工作正常、防火墙已放行):

Export list for 192.168.0.183:
/soul *
选项 作用
-e 显示服务端的导出列表
-d 显示已被客户端挂载的目录
-a 显示"客户端:目录"的完整挂载清单

7.2 临时挂载

# 简写形式(自动识别为 nfs 类型)
mount 10.0.0.2:/test /mnt
sudo mount 192.168.0.183:/soul /mnt

# 显式指定文件系统类型
sudo mount -t nfs 192.168.0.183:/soul /mnt

# 指定挂载选项
sudo mount -t nfs -o rw,soft,timeo=30,retrans=3 192.168.0.183:/soul /mnt

挂载后验证:

df -h
mount | grep nfs

进入 /mnt 即可看到共享内容,可像操作本地目录一样操作网络共享目录。

7.3 mount 常用选项

选项 说明
rw / ro 以读写 / 只读方式挂载(最终权限还受服务端 /etc/exports 限制,两者取交集)
hard 服务端无响应时无限重试(默认)。可靠但服务端宕机会导致访问进程卡死
soft 重试 retrans 次后返回 I/O 错误,进程不会永久卡死(服务端不稳定时推荐)
intr 允许用 Ctrl+C 中断卡在 NFS 上的进程(新内核已默认支持,旧系统需显式指定)
timeo=n 每次请求的超时时间,单位为 0.1 秒,timeo=30 即 3 秒
retrans=n 超时后的重试次数
bg / fg 首次挂载失败时转入后台重试 / 在前台重试(开机挂载建议 bg,避免卡住启动流程)
rsize=n / wsize=n 读/写数据块大小(字节),如 rsize=32768,一般交给系统自动协商即可
nfsvers=3 / vers=4 指定 NFS 协议版本(3 或 4)
proto=tcp / proto=udp 指定传输协议,生产环境建议 tcp
noatime 不更新访问时间,减少写操作,提升性能
nosuid 忽略共享中的 SUID/SGID 位,提升安全性
nodev 忽略共享中的设备文件
actimeo=n 属性缓存时间(秒),设为 0 可关闭缓存,保证多客户端间元数据实时一致
_netdev 声明该挂载依赖网络,用于 /etc/fstab,见 7.5

7.4 卸载

sudo umount /mnt

# 强制取消挂载(lazy umount,用于服务端已失联、普通 umount 卡住时)
sudo umount -l /mnt

# 强制卸载(另一种方式)
sudo umount -f /mnt

7.5 fstab 持久化与 _netdev

写入 /etc/fstab 可实现开机自动挂载:

sudo vim /etc/fstab
# 设备(服务端:共享目录)      挂载点   类型  挂载选项                             dump  fsck
192.168.0.183:/soul         /mnt     nfs   defaults,_netdev,soft,bg,noatime      0     0

字段说明与关键选项:

选项 为什么需要
_netdev 必须加。声明该文件系统依赖网络,系统会等网络就绪后再挂载。不加则可能在网络未启动时就尝试挂载而失败
bg 首次挂载失败转后台重试,避免服务端未开机时卡住整个开机流程
soft 服务端失联时返回错误而不是无限等待
noauto 开机不自动挂载,仅登记配置,之后手工 mount /mnt 即可(最保险的折中方案)
最后两列 网络文件系统的 dump 与 fsck 均填 0,不参与本地备份与文件系统检查

验证 fstab 是否写对(务必在重启前验证):

# 按 fstab 挂载所有未挂载项,可提前发现写错
sudo mount -a

# CentOS 7 可再确认 systemd 已识别
sudo systemctl daemon-reload

⚠️ 强烈提醒:/etc/fstab 写错(尤其是漏掉 _netdev / bg)可能导致系统无法正常开机,必须进单用户模式修复。改完一定先 mount -a 验证,再重启。

四种开机自动挂载方式的对比:

方式 说明 评价
/etc/fstab 开机静态挂载 服务端宕机时挂载点卡死,df -h 等命令都会挂住,不推荐
/etc/rc.local 开机脚本中执行 mount 同上问题,不推荐
命令别名 用 alias 简化手工挂载命令 只是省了打字,不算自动挂载
autofs 访问时才挂载,空闲超时自动卸载 推荐,见第九章

八、权限与用户映射问题

NFS 本身不做用户名密码认证,它靠"客户端 IP + UID/GID"来判断权限。这带来了教学与生产中最常见的一类困惑。

8.1 最终权限 = 三者取交集

客户端某个用户能否写入共享目录,取决于三层限制同时满足:

  1. /etc/exports 的导出选项:写了 ro 就绝对无法写入,客户端加 -o rw 也没用。
  2. 服务端本地目录的文件系统权限:即共享目录在服务端上的 owner/group/mode。导出成 rw 但目录本身是 755 root:root,普通用户依然写不进去。
  3. 客户端挂载时的选项:客户端用 -o ro 挂载,则即使服务端允许 rw 也只能读。

排查"明明配了 rw 却写不进去"时,九成的原因是第 2 条:忘了在服务端调整共享目录本身的权限或属主。

8.2 UID/GID 是按数字匹配的

NFS 在网络上传递的是 UID/GID 数字,而不是用户名。因此:

  • 服务端 /data 属主是 UID 1000,客户端上恰好有个 UID 也是 1000 的用户(哪怕名字完全不同),该用户就拥有该目录的属主权限。
  • 反之,客户端的 zhangsan(UID 1001)与服务端的 zhangsan(UID 1000)会被视为两个不同的用户。

解决思路(生产环境三选一):

方案 做法 适用场景
统一 UID/GID 在所有节点用相同 UID/GID 创建同名用户(useradd -u 1000 -g 1000 www) 节点较少、可控
全部压缩为匿名用户 导出时加 all_squash,anonuid=1000,anongid=1000,并把服务端目录属主改成该 UID/GID 共享上传目录、Web 附件目录,最常用
统一认证 使用 LDAP / NIS 集中管理账号,或使用 NFSv4 + Kerberos 的 idmapd 名称映射 规模较大的环境

all_squash 方案的完整示例:

# 服务端:创建统一的属主并调整目录权限
sudo groupadd -g 1000 nfsuser
sudo useradd -u 1000 -g 1000 -M -s /sbin/nologin nfsuser
sudo mkdir -p /data
sudo chown -R nfsuser:nfsuser /data
sudo chmod 755 /data
# /etc/exports
/data    192.168.0.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000)
sudo exportfs -arv

这样,无论客户端用哪个用户写入,落到服务端的文件属主统一为 nfsuser,权限清晰可控。

8.3 root_squash:为什么客户端 root 反而没权限

root_squash 默认启用:客户端 root(UID 0)的请求会被映射为匿名用户(nfsnobody,通常 UID 65534)。因此会出现"客户端明明是 root,却在共享目录里创建不了文件"的现象——这是正常且正确的安全设计。

处理方式:

  • 推荐:按 8.2 的 all_squash 方案规划权限,让服务端目录属主与匿名 UID 一致。
  • 特殊场景(无盘系统、需要客户端 root 完全控制)才使用 no_root_squash,并严格限制可访问的客户端 IP:
/tftpboot    192.168.0.50(rw,sync,no_root_squash)

no_root_squash 意味着任何能挂载该共享的机器上的 root 都等于服务端上的 root,可修改共享内的一切文件(包括设置 SUID 程序)。*不要对 `` 或整个网段使用它。**

8.4 SELinux 的影响

SELinux 处于 enforcing 状态时会阻止 NFS 的读写。

# 查看状态,Permissive 或 Disabled 表示不拦截
getenforce

# 临时关闭
sudo setenforce 0

永久关闭,编辑 /etc/selinux/config:

SELINUX=disabled

生产环境更规范的做法是放行对应布尔值(如 setsebool -P nfs_export_all_rw on)而不是直接关闭 SELinux。教学环境为简化操作可先关闭。


九、autofs 自动挂载

9.1 为什么使用 autofs

NFS 客户端实现开机自动挂载有四种方式:/etc/fstab、/etc/rc.local、命令别名、autofs。

前两种方式不推荐:如果客户端已经配置了开机自动挂载,而 NFS 服务器关机后客户端没有及时 umount,挂载点会卡死,导致 df -h、ls、cd 等命令全部无法使用,甚至新终端都登录不进去。

autofs 是一种 按需挂载(on-demand mount) 机制:

  • 只有当用户实际访问挂载点时才触发挂载;
  • 一段时间不使用后自动卸载;
  • 服务端不可用时,未访问的挂载点根本不存在,因此不会拖垮整台机器。

说明:autofs 与 U 盘插入后的桌面自动挂载无关(后者由 udisks/udev 负责)。autofs 是针对网络文件系统、光驱、ISO 镜像等的按需自动挂载服务。

9.2 安装与启动

安装:

yum install -y autofs

启动(CentOS 6 / RHEL 5/6):

/etc/init.d/autofs restart
# 或
/etc/rc.d/init.d/autofs restart
# 或
service autofs restart

chkconfig autofs on

输出示例:

Stopping automount:                                        [  OK  ]
Starting automount:                                        [  OK  ]

启动(CentOS 7 / RHEL 7):

sudo systemctl restart autofs
sudo systemctl enable --now autofs
sudo systemctl status autofs
操作 CentOS 6 CentOS 7
重启 service autofs restart / /etc/init.d/autofs restart systemctl restart autofs
开机自启 chkconfig autofs on systemctl enable autofs
主超时参数位置 /etc/sysconfig/autofs 中 TIMEOUT /etc/sysconfig/autofs 中 TIMEOUT(亦可用 /etc/autofs.conf)

9.3 配置文件结构

文件 作用
/etc/auto.master 主映射文件,定义"挂载父目录"与"子配置文件"的对应关系
/etc/auto.misc 子配置文件(系统自带示例,默认配合 /misc 使用)
/etc/auto.nfs、/etc/auto.direct 等 自建的子配置文件,定义具体挂载点、选项与设备/共享路径
/etc/auto.master.d/*.autofs 主映射的片段目录(较新版本支持,便于按服务拆分配置)
/etc/sysconfig/autofs 服务运行参数,如超时时间 TIMEOUT、浏览模式 BROWSE_MODE

主映射文件格式:

挂载父目录   子配置文件   [选项]

子配置文件格式:

挂载点名   -挂载选项   设备或远程共享路径

子配置文件中挂载选项以 - 开头。无特殊选项时也要保留一个 - 占位,例如 software - 10.1.1.1:/external/software。有选项时写成 -rw、-ro、-rw,soft、-fstype=nfs 等。

语法细节可参考 man 5 autofs(讲义中写作 man autofs(5))与 man 5 auto.master。

9.4 间接映射(indirect map,最常用)

间接映射的特点:主映射文件里给出一个父目录,子配置文件里的每一项都是该父目录下的一个子目录名。

第 1 步:在主配置文件中添加一条记录

vim /etc/auto.master
/nfs /etc/auto.nfs

含义:把 /etc/auto.nfs 中定义的所有设备挂载到 /nfs 目录下。挂载点 /nfs 无需手动创建,autofs 会自行管理。

第 2 步:创建子配置文件

vim /etc/auto.nfs
software - 10.1.1.1:/external/software

第 3 步:重启服务

# CentOS 6
service autofs restart
# CentOS 7
sudo systemctl restart autofs

结果:10.1.1.1:/external/software 会被挂载到 /nfs/software。该目录平时并不存在,首次访问(cd /nfs/software 或 ls /nfs/software)时 autofs 会自动创建挂载点并完成挂载;空闲超时后自动卸载并删除挂载点(是否显示未挂载的挂载点受 BROWSE_MODE 影响)。

多个共享的写法:

# /etc/auto.nfs
software  -rw,soft        10.1.1.1:/external/software
backup    -ro            10.1.1.1:/data/backup
yum       -rw,sync       192.168.0.109:/yum

对应的访问路径分别是 /nfs/software、/nfs/backup、/nfs/yum。

9.5 直接映射(direct map)

直接映射用于把远程共享挂载到文件系统中任意已有的绝对路径,而不是集中在某个父目录下。主映射文件中父目录位置写特殊标记 /-:

# /etc/auto.master
/-    /etc/auto.direct
# /etc/auto.direct:挂载点必须写完整的绝对路径
/mnt/nfsdata      -rw,sync     192.168.0.109:/yum
/opt/software     -ro          10.1.1.1:/external/software

重启后访问 /mnt/nfsdata 即触发挂载。

间接映射与直接映射对比:

对比项 间接映射 直接映射
主映射中的父目录 具体目录,如 /nfs 固定写 /-
子配置中的挂载点 相对名称,如 software 完整绝对路径,如 /mnt/nfsdata
实际路径 父目录 + 名称(/nfs/software) 就是写的那个路径
父目录是否被 autofs 独占 是,父目录内容完全由 autofs 管理,不能放其他文件 否,可挂到已有目录树的任意位置
未挂载时挂载点是否可见 取决于 BROWSE_MODE 目录始终可见
适用场景 一批共享集中管理(最常用) 必须挂到指定既有路径(如 /home/xxx、/opt/xxx)

9.6 通配符映射(自动匹配同名共享)

当服务端有大量结构相同的共享(如为每个用户导出一个家目录)时,用通配符可以一条规则搞定:

# /etc/auto.master
/home    /etc/auto.home
# /etc/auto.home
*    -rw,soft    192.168.0.183:/export/home/&

规则说明:

符号 含义
* 匹配用户访问的任意子目录名(作为键)
& 在远端路径中被替换为 * 实际匹配到的内容

效果:访问 /home/u1 时自动挂载 192.168.0.183:/export/home/u1;访问 /home/u2 时自动挂载 192.168.0.183:/export/home/u2,无需为每个用户单独写一行。这是 NFS 共享家目录的标准做法。

9.7 超时卸载与 /etc/sysconfig/autofs

/etc/sysconfig/autofs 中两个值得注意的参数:

TIMEOUT=10
BROWSE_MODE="yes"
参数 说明
TIMEOUT=10 空闲超时时间(秒)。超过设定时间未访问则自动卸载。默认约 300 秒(5 分钟)
BROWSE_MODE="yes" 浏览模式。设为 yes 时,即使尚未挂载也在父目录中显示挂载点(ls 能看到子目录名);设为 no 时未挂载的挂载点不可见

也可以在 /etc/auto.master 中为单个映射单独指定超时时间,优先级高于全局配置:

/nfs    /etc/auto.nfs    --timeout=60
/misc   /etc/auto.misc   --timeout=300

改完配置后必须重启服务:

sudo systemctl restart autofs      # CentOS 7
service autofs restart             # CentOS 6

默认超时约 5 分钟,因此课堂测试时"访问后有内容、等一会儿目录就消失了"是正常现象,不是配置错误。若想快速看到卸载效果,把 TIMEOUT 调小(如 10 秒)再测试。

CentOS 7 较新版本也支持在 /etc/autofs.conf 的 [autofs] 段中设置 timeout= 与 browse_mode=,两处配置作用等价。

9.8 实例一:autofs 自动挂载 NFS

第 1 步:在主配置文件末尾添加一行

vim /etc/auto.master
/mnt    /etc/auto.nfs

第 2 步:创建子配置文件

vim /etc/auto.nfs
nfs    -rw    192.168.0.109:/yum

含义:将 192.168.0.109 上的 /yum 共享,以可读写方式自动挂载到客户端的 /mnt/nfs。

第 3 步:重启服务

# CentOS 6
/etc/rc.d/init.d/autofs restart
# CentOS 7
sudo systemctl restart autofs

输出:

Stopping automount:                                        [  OK  ]
Starting automount:                                        [  OK  ]

第 4 步:验证

ls /mnt          # 为空(尚未访问,未触发挂载)
ls /mnt/nfs      # 有内容表示挂载成功
df -h            # 可看到 NFS 挂载项
                 # 约 5 分钟不使用后自动卸载

9.9 实例二:autofs 自动挂载光驱

主配置文件:

vim /etc/auto.master
/misc   /etc/auto.misc

子配置文件:

vim /etc/auto.misc
cd    -fstype=iso9660,ro,nosuid,nodev    :/dev/cdrom

含义:/dev/cdrom 以 iso9660 文件系统、只读、nosuid、nodev 参数自动挂载到 /misc/cd。

本地设备路径前要加冒号(:/dev/cdrom),这是 autofs 区分"本地设备"与"远程共享"的写法。

测试:

/etc/init.d/autofs restart     # CentOS 6
# sudo systemctl restart autofs  # CentOS 7

ls /misc         # 此时为空,因为尚未访问
ls /misc/cd      # 访问时触发自动挂载,可看到光盘/ISO 内容
ls /misc         # 约 5 分钟不使用后,cd 目录会自动消失(已卸载)

9.10 常用挂载配置格式参考(NFS / Samba / ISO / U 盘)

# 挂载 Samba(CIFS)共享,username%password 形式提供凭据
backup   -fstype=cifs,username=smbuser1%asdf    ://192.168.1.99/pub

# 以 loop 方式挂载本地 ISO 镜像文件
iso      -loop,fstype=iso9660,ro    :/root/rhel-server-6.0-x86_64-boot.iso

# 挂载 NFS(显式指定 fstype)
nfs      -fstype=nfs    192.168.1.99:/test_nfs

# 挂载光驱
cd       -fstype=iso9660,ro,nosuid,nodev    :/dev/cdrom

# 挂载 U 盘 / 移动硬盘的固定分区(设备名可用 /dev/sdb1,更稳妥的是用 UUID)
usb      -fstype=vfat,rw,nosuid,nodev,uid=1000,gid=1000    :/dev/sdb1
usb2     -fstype=auto,rw,nosuid,nodev    :UUID=1234-ABCD

关于 U 盘:autofs 只能对设备节点固定的移动存储做按需挂载(因此建议用 UUID= 而不是可能变化的 /dev/sdb1)。它并不负责"插入 U 盘就自动出现在桌面"这类热插拔响应,那是 udev/udisks 的工作。-fstype=auto 可让内核自动探测文件系统类型(vfat/exfat/ntfs 等),其中 exfat/ntfs 可能需要额外安装 fuse-exfat、ntfs-3g。


十、排错清单

10.1 通用排查顺序(自下而上、由服务端到客户端)

# ===== 服务端 =====
# 1. 服务是否在运行
systemctl status rpcbind nfs-server        # CentOS 7
service rpcbind status; service nfs status # CentOS 6

# 2. RPC 是否注册成功(必须能看到 nfs / mountd 条目)
rpcinfo -p localhost

# 3. 实际生效的导出配置是否与 /etc/exports 一致
exportfs -v
cat /var/lib/nfs/etab

# 4. 端口是否在监听
ss -tunlp | grep -E '111|2049'

# 5. 防火墙与 SELinux
firewall-cmd --list-all        # CentOS 7
iptables -L -n                 # CentOS 6
getenforce

# 6. 共享目录本身的权限
ls -ld /data

# ===== 客户端 =====
# 7. 网络连通性
ping -c 2 192.168.0.183

# 8. 能否看到服务端的导出列表(这一步能过,说明网络+rpcbind+mountd 都正常)
showmount -e 192.168.0.183

# 9. 挂载并查看详细报错
mount -t nfs -v 192.168.0.183:/soul /mnt

# 10. 日志
tail -f /var/log/messages
journalctl -xe                 # CentOS 7

10.2 常见故障对照表

现象 / 报错 原因 处理
mount 或 showmount 长时间卡住无响应 防火墙丢弃了数据包(DROP 而非 REJECT);或服务端已宕机 服务端 systemctl stop firewalld / iptables -F 后重试;固定端口并按 6.2/6.3 精确放行
clnt_create: RPC: Program not registered 服务端 nfs 服务未启动(只起了 rpcbind) 服务端 systemctl start nfs-server(CentOS 6:service nfs start)
rpcbind: server localhost not responding / RPC: Unable to receive rpcbind 未启动 先启 rpcbind,再启 nfs;顺序错了要把 nfs 重启一次以重新注册
mount.nfs: access denied by server while mounting 客户端 IP 不在 /etc/exports 允许范围内;或指定 IP 时漏写掩码;或修改配置后未 exportfs -arv 核对 exportfs -v 的实际生效内容;网段必须写 /24 或 /255.255.255.0
mount.nfs: no such file or directory 服务端共享目录不存在;或客户端挂载点不存在 两端都 mkdir -p 建好目录
mount: wrong fs type, bad option... 客户端未安装 nfs-utils,缺少 NFS 挂载支持 客户端 yum -y install nfs-utils
挂载成功但只能读不能写 /etc/exports 写的是 ro(默认值);或客户端用 -o ro 挂载 改为 rw 并 exportfs -arv;客户端重新以 rw 挂载
导出了 rw,普通用户仍写不进去 服务端共享目录本身的属主/权限不允许 在服务端 chown / chmod,参见 8.1、8.2
客户端 root 也无法创建文件 root_squash 默认生效,root 被映射为匿名用户 采用 all_squash + anonuid/anongid 规划权限;确有必要才用 no_root_squash
写入的文件属主显示为 nobody / 65534 匿名映射生效,或两端 UID/GID 不一致 统一 UID/GID,或用 anonuid/anongid 指定并同步服务端目录属主
权限被莫名拒绝,日志有 avc: denied SELinux 拦截 getenforce 确认;setenforce 0 临时放开,或放行相应布尔值
CentOS 7 上"防火墙已关"却仍连不上 只执行了 iptables -F,firewalld 规则仍在生效 systemctl stop firewalld,或用 firewall-cmd 放行 nfs/mountd/rpc-bind
服务端宕机后客户端 df -h、ls 全部卡死 用 /etc/fstab 或 rc.local 做了 hard 挂载 umount -l 强制卸载;改用 autofs,或挂载时加 soft,bg,_netdev
写入 fstab 后系统无法开机 漏写 _netdev / bg,网络未就绪时挂载阻塞 单用户模式改回;今后改完必须先 mount -a 验证
autofs 配好了,ls 父目录却是空的 这是正常现象:未访问就不挂载 直接 ls 父目录/挂载点名 触发;或设 BROWSE_MODE="yes"
autofs 完全不触发挂载 子配置文件缺少 - 占位;挂载点名写成了绝对路径(间接映射中不允许);改完未重启服务 检查语法(man 5 autofs);systemctl restart autofs;用 automount -f -v 前台运行看实时日志
autofs 挂上后很快就掉了 TIMEOUT 设得过小 调大 /etc/sysconfig/autofs 中的 TIMEOUT,或在 auto.master 中用 --timeout= 单独指定
autofs 与 fstab 同时管理同一目录 两套机制冲突,表现为反复挂载/卸载 一个挂载点只用一种方式管理,从 fstab 中删除对应行

10.3 三个最容易忽略的配置陷阱

配置 NFS 时最常见的三个问题(务必优先检查):

  1. 防火墙挡住了客户端的请求(CentOS 7 还要注意 firewalld 与 iptables 是两套东西)。
  2. SELinux 阻止了客户端的请求。
  3. NFS 配置文件中用 IP 地址指定一台主机,但忘了加上子网掩码(想放开网段却只写了网络号)。

10.4 调试技巧

# 前台运行 automount 并输出详细日志,是排查 autofs 最有效的手段
sudo systemctl stop autofs
sudo automount -f -v

# 挂载时输出详细过程
sudo mount -t nfs -v 192.168.0.183:/soul /mnt

# 查看客户端当前所有 NFS 挂载及其生效选项
mount -t nfs
cat /proc/mounts | grep nfs

# 查看服务端 NFS 统计信息(请求量、错误数)
nfsstat -s     # 服务端视角
nfsstat -c     # 客户端视角

十一、练习

练习 1:搭建 NFS 共享(两人一组配合完成)

  1. 服务端:安装 nfs-utils 与 rpcbind,将自己作为软件仓库的目录(如 /yum)通过 NFS 共享出来,要求其他人挂载后拥有可读可写权限。
  2. 服务端:使用 exportfs -arv 重载配置,用 exportfs -v 与 rpcinfo -p localhost 确认生效。
  3. 客户端:用 showmount -e <服务端IP> 查看共享列表。
  4. 客户端:用 mount 临时挂载到 /mnt,用 df -h 验证,并实际创建一个文件确认可写。
  5. 排查过程中如挂载失败,按第十章的清单依次检查防火墙、SELinux、/etc/exports 中的掩码。

练习 2:autofs 自动挂载 NFS

  1. 将练习 1 中的共享目录配置为 autofs 自动挂载,挂载后同样拥有可读可写权限。
  2. 在 /etc/auto.master 中添加父目录与子配置文件的对应关系,并编写子配置文件。
  3. 重启 autofs 后,先 ls 父目录(应为空),再 ls 挂载点(触发挂载),观察 df -h 变化。
  4. 把 /etc/sysconfig/autofs 中的 TIMEOUT 改为 10 秒,等待后再次 df -h,观察自动卸载效果。
  5. 对比 BROWSE_MODE="yes" 与 "no" 时 ls 父目录的差异。

练习 3:权限映射实验

  1. 服务端导出目录时分别使用 root_squash(默认)与 no_root_squash,在客户端以 root 身份创建文件,对比结果与文件属主。
  2. 服务端改用 all_squash,anonuid=1000,anongid=1000,并把共享目录属主改为对应 UID/GID,在客户端用不同普通用户写入,观察落地文件的属主是否统一。
  3. 在客户端建立一个与服务端 UID 相同但用户名不同的账号,验证 NFS 是按 UID 数字而非用户名判权。

练习 4:直接映射、间接映射与通配符映射

  1. 用间接映射把服务端两个不同共享分别挂到 /nfs/software 与 /nfs/backup。
  2. 用直接映射把某个共享挂到已存在的 /opt/software 目录。
  3. 服务端在 /export/home/ 下建立 u1、u2 两个子目录并分别导出,客户端用通配符映射实现访问 /home/u1、/home/u2 时自动挂载对应目录。

练习 5:光驱与 ISO 的 autofs 挂载

  1. 配置 /etc/auto.master 与 /etc/auto.misc,实现访问 /misc/cd 时自动挂载光驱。
  2. 再增加一条规则,用 -loop,fstype=iso9660,ro 方式自动挂载一个本地 ISO 文件。
  3. 观察超时后挂载点消失的现象。

练习 6:端口固定与防火墙放行

  1. 未固定端口时,连续两次重启 nfs 服务,用 rpcinfo -p localhost 对比 mountd、statd 的端口是否发生变化。
  2. 编辑 /etc/sysconfig/nfs 固定端口,重启服务后再次对比。
  3. 编写 iptables 规则批量放行这些端口(含 111 与 2049),并在客户端验证挂载成功。
  4. CentOS 7 上改用 firewall-cmd --permanent --add-service={nfs,mountd,rpc-bind} 完成同样的放行,对比两种方式。

练习 7:fstab 持久化与故障模拟

  1. 将 NFS 共享写入 /etc/fstab,加上 _netdev,soft,bg,用 mount -a 验证后重启确认自动挂载成功。
  2. 关闭 NFS 服务端,在客户端执行 df -h 与 ls 挂载点,观察是否卡住(对比 soft 与 hard 的差异)。
  3. 用 umount -l 处理卡住的挂载点。
  4. 把该挂载改造为 autofs 管理,再次关闭服务端,验证客户端命令不再卡死。

十二、命令速查表

场景 命令
查询是否安装 NFS rpm -qa nfs* / rpm -qa portmap
安装 NFS yum -y install nfs-utils(RHEL5:yum install portmap -y; yum install nfs* -y)
安装 autofs yum -y install autofs
启动 rpcbind(CentOS 6) service rpcbind start / /etc/init.d/rpcbind start
启动 NFS(CentOS 6) service nfs start / /etc/init.d/nfs start
开机自启(CentOS 6) chkconfig rpcbind on + chkconfig nfs on
启动 NFS(CentOS 7) systemctl start nfs-server(别名 nfs.service)
开机自启(CentOS 7) systemctl enable --now rpcbind nfs-server
查看 RPC 注册信息 rpcinfo -p localhost / rpcinfo -p <服务端IP>
编辑导出配置 vim /etc/exports
重载导出配置(不重启服务) exportfs -arv
查看实际生效的导出 exportfs -v / cat /var/lib/nfs/etab
取消全部导出 exportfs -auv
查看服务端共享列表 showmount -e <IP>
查看已被挂载的目录 showmount -d <IP> / showmount -a <IP>
挂载 NFS mount <IP>:/share /mnt / mount -t nfs <IP>:/share /mnt
带选项挂载 mount -t nfs -o rw,soft,timeo=30 <IP>:/share /mnt
卸载 umount /mnt
强制卸载(服务端失联) umount -l /mnt / umount -f /mnt
fstab 持久化 <IP>:/share /mnt nfs defaults,_netdev,soft,bg 0 0
验证 fstab mount -a
查看挂载情况 mount / df -h / mount -t nfs
NFS 统计信息 nfsstat -s(服务端) / nfsstat -c(客户端)
固定 NFS 端口 编辑 /etc/sysconfig/nfs 后重启 rpcbind 与 nfs
放行防火墙(iptables) iptables -I INPUT -p tcp --dport 2049 -j ACCEPT(另需 111 及固定端口)
放行防火墙(firewalld) firewall-cmd --permanent --add-service={nfs,mountd,rpc-bind} + --reload
清空 iptables 规则 iptables -F
停止 firewalld(CentOS 7) systemctl stop firewalld
查看/关闭 SELinux getenforce / setenforce 0
autofs 主映射文件 /etc/auto.master
autofs 子映射文件 /etc/auto.nfs、/etc/auto.misc、/etc/auto.direct
autofs 运行参数 /etc/sysconfig/autofs(TIMEOUT、BROWSE_MODE)
重启 autofs systemctl restart autofs(CentOS 6:service autofs restart)
autofs 前台调试 systemctl stop autofs + automount -f -v
查看手册 man exports / man 5 autofs / man 5 auto.master
最后修改:2026 年 09 月 20 日
如果觉得我的文章对你有用,请随意赞赏