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(选项...) ...]
书写规则(三条容易出错的细节):
- 共享目录必须顶格写,行首不能有空格或制表符。
- 客户端与紧跟其后的括号之间不能有空格。
/test 10.0.0.11(rw)是"10.0.0.11 可读写";写成/test 10.0.0.11 (rw)则变成"10.0.0.11 使用默认选项"外加"所有主机可读写",是严重的安全事故。 - 同一行可以为多个不同客户端指定不同权限,用空格分隔。
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 最终权限 = 三者取交集
客户端某个用户能否写入共享目录,取决于三层限制同时满足:
/etc/exports的导出选项:写了ro就绝对无法写入,客户端加-o rw也没用。- 服务端本地目录的文件系统权限:即共享目录在服务端上的
owner/group/mode。导出成rw但目录本身是755 root:root,普通用户依然写不进去。 - 客户端挂载时的选项:客户端用
-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 时最常见的三个问题(务必优先检查):
- 防火墙挡住了客户端的请求(CentOS 7 还要注意 firewalld 与 iptables 是两套东西)。
- SELinux 阻止了客户端的请求。
- 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 共享(两人一组配合完成)
- 服务端:安装
nfs-utils与rpcbind,将自己作为软件仓库的目录(如/yum)通过 NFS 共享出来,要求其他人挂载后拥有可读可写权限。 - 服务端:使用
exportfs -arv重载配置,用exportfs -v与rpcinfo -p localhost确认生效。 - 客户端:用
showmount -e <服务端IP>查看共享列表。 - 客户端:用
mount临时挂载到/mnt,用df -h验证,并实际创建一个文件确认可写。 - 排查过程中如挂载失败,按第十章的清单依次检查防火墙、SELinux、
/etc/exports中的掩码。
练习 2:autofs 自动挂载 NFS
- 将练习 1 中的共享目录配置为 autofs 自动挂载,挂载后同样拥有可读可写权限。
- 在
/etc/auto.master中添加父目录与子配置文件的对应关系,并编写子配置文件。 - 重启 autofs 后,先
ls父目录(应为空),再ls挂载点(触发挂载),观察df -h变化。 - 把
/etc/sysconfig/autofs中的TIMEOUT改为 10 秒,等待后再次df -h,观察自动卸载效果。 - 对比
BROWSE_MODE="yes"与"no"时ls父目录的差异。
练习 3:权限映射实验
- 服务端导出目录时分别使用
root_squash(默认)与no_root_squash,在客户端以 root 身份创建文件,对比结果与文件属主。 - 服务端改用
all_squash,anonuid=1000,anongid=1000,并把共享目录属主改为对应 UID/GID,在客户端用不同普通用户写入,观察落地文件的属主是否统一。 - 在客户端建立一个与服务端 UID 相同但用户名不同的账号,验证 NFS 是按 UID 数字而非用户名判权。
练习 4:直接映射、间接映射与通配符映射
- 用间接映射把服务端两个不同共享分别挂到
/nfs/software与/nfs/backup。 - 用直接映射把某个共享挂到已存在的
/opt/software目录。 - 服务端在
/export/home/下建立u1、u2两个子目录并分别导出,客户端用通配符映射实现访问/home/u1、/home/u2时自动挂载对应目录。
练习 5:光驱与 ISO 的 autofs 挂载
- 配置
/etc/auto.master与/etc/auto.misc,实现访问/misc/cd时自动挂载光驱。 - 再增加一条规则,用
-loop,fstype=iso9660,ro方式自动挂载一个本地 ISO 文件。 - 观察超时后挂载点消失的现象。
练习 6:端口固定与防火墙放行
- 未固定端口时,连续两次重启
nfs服务,用rpcinfo -p localhost对比mountd、statd的端口是否发生变化。 - 编辑
/etc/sysconfig/nfs固定端口,重启服务后再次对比。 - 编写 iptables 规则批量放行这些端口(含
111与2049),并在客户端验证挂载成功。 - CentOS 7 上改用
firewall-cmd --permanent --add-service={nfs,mountd,rpc-bind}完成同样的放行,对比两种方式。
练习 7:fstab 持久化与故障模拟
- 将 NFS 共享写入
/etc/fstab,加上_netdev,soft,bg,用mount -a验证后重启确认自动挂载成功。 - 关闭 NFS 服务端,在客户端执行
df -h与ls 挂载点,观察是否卡住(对比soft与hard的差异)。 - 用
umount -l处理卡住的挂载点。 - 把该挂载改造为 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 |
此处评论已关闭