Skip to content

NFS 基础运维

NFS 是一种文件共享协议,不是块存储。服务端把本地目录通过 NFS 导出,客户端挂载后像访问本地目录一样读写——实际数据落在服务端磁盘上。

它的价值是"让多台机器看到同一个目录"。代价包括服务端性能瓶颈、网络延迟、UID/GID 权限映射和单点故障。这些代价不会因为装了 NFS 就消失——故障现场需要用正确的排查手段找到对应的问题层。

常见适用场景

场景适合的原因
共享软件安装包多台机器挂同一个只读目录,减少分发
备份落点各业务机器把备份文件写到统一 NFS 目录
内部脚本和附件目录轻量共享,读写频率低
K8s 实验存储NFS 目录直接映射给 PV,数据落点可见
老系统过渡存量系统依赖共享目录,短期内用 NFS 承接

NFS 不天然提供跨节点高可用和数据多副本。底层用单机磁盘时 NFS 就是单点;用 RAID、云盘或双机方案,单点风险转移到了对应层面——但 NFS 自身没有消除它。

版本选择

版本特点
NFSv3老环境常见,依赖 rpcbind/mountd/statd 多端口,防火墙管理更重
NFSv4核心端口 2049,ACL 和身份映射比 v3 清晰
NFSv4.1/4.2会话增强、并行 NFS(pNFS)能力,新系统默认方向

生产里固定 vers=4.14.2 比让客户端和服务端自动协商更可控。老 NAS 可能只支持 v3,此时要把 rpcbind、mountd、statd 的端口和防火墙规则一起记录——v3 不是单端口协议,仅开 2049 不够。

服务端部署

示例环境:

主机IP角色
nfs01192.168.10.20服务端
app01192.168.10.31客户端
app02192.168.10.32客户端

RHEL/Rocky/CentOS 服务端:

bash
yum install -y nfs-utils

# UID/GID 在所有客户端上保持一致,避免多台机器同名用户但数字不同
groupadd -g 10001 appdata || true
useradd -u 10001 -g appdata -M -s /sbin/nologin appdata || true

mkdir -p /data/nfs/share
chown appdata:appdata /data/nfs/share
chmod 2770 /data/nfs/share       # 2770: 组继承,同组用户可直接写入

Ubuntu/Debian:

bash
apt-get update
apt-get install -y nfs-kernel-server

mkdir -p /data/nfs/share
chown 10001:10001 /data/nfs/share
chmod 2770 /data/nfs/share

编写 /etc/exports

bash
# root_squash: 客户端 root 映射成匿名用户,防止远端 root 以 root 身份写服务端文件
/data/nfs/share 192.168.10.0/24(rw,sync,no_subtree_check,root_squash)
bash
systemctl enable --now nfs-server
exportfs -rav          # 重新读 exports 并生效
showmount -e 127.0.0.1 # 确认导出成功

exports 参数

一行 exports 由导出目录、客户端范围、参数三部分组成:

参数效果
rw / ro读写 / 只读导出
sync写入同步落盘再返回——更安全,但性能低于 async
async异步返回——性能更好,异常断电时数据丢失风险更高
root_squash客户端 root 映射成匿名用户(通常是 nobody)
no_root_squash客户端 root 保持 root 身份——风险很大,只适合特定场景
all_squash所有客户端用户都映射成匿名用户
anonuid/anongid配合 all_squash,指定匿名用户映射到哪个 UID/GID
no_subtree_check关闭子目录检查,减少文件系统子树变化时的报错

权限问题的根因很多不是 NFS 协议坏了,而是 UID/GID 在客户端和服务端上不一致。文件系统认的是数字 UID,不是用户名字符串。app01appdata 是 UID 1001,nfs01appdata 是 UID 10001——权限鉴定结果完全不同。

把应用用户在所有参与 NFS 的机器上统一成相同 UID/GID,比事后到处 chmod 777 更稳。chmod 777 + no_root_squash 实验省事,但生产里任何客户端都能用 root 身份写服务端文件。

客户端挂载

RHEL/Rocky/CentOS:

bash
yum install -y nfs-utils
showmount -e 192.168.10.20    # 先确认服务端导出成功了
mkdir -p /mnt/share

# vers 固定版本,hard 表示服务端异常时等待恢复而非静默丢数据
mount -t nfs -o vers=4.1,hard,timeo=600,retrans=2 192.168.10.20:/data/nfs/share /mnt/share

Ubuntu/Debian:

bash
apt-get update && apt-get install -y nfs-common
showmount -e 192.168.10.20
mkdir -p /mnt/share
mount -t nfs -o vers=4.1,hard,timeo=600,retrans=2 192.168.10.20:/data/nfs/share /mnt/share

用应用用户身份验证写入(比 root 测试更接近生产条件):

bash
sudo -u appdata bash -c 'date >> /mnt/share/write-test.log'
tail /mnt/share/write-test.log

# 回服务端确认文件确实存在且属主正确
ssh nfs01 'ls -l /data/nfs/share/write-test.log && tail /data/nfs/share/write-test.log'

df -h 里出现挂载点只说明 mount 命令执行了。应用能不能真正写入,要拿应用的用户身份测一遍。

fstab 和自动挂载

fstab
192.168.10.20:/data/nfs/share /mnt/share nfs vers=4.1,hard,timeo=600,retrans=2,_netdev 0 0
参数含义
vers=4.1固定版本
hard服务端异常时 IO 阻塞等待恢复——写入类业务偏向 hard
soft服务端异常时返回 IO error——临时读取或不接受阻塞的可评估
timeo=600RPC 超时,单位 0.1 秒
retrans=2重传次数
_netdev标记为网络设备,等网络就绪后再挂载

改完 fstab 先用 mount -a 测试:

bash
mount -a
df -hT /mnt/share

对启动顺序敏感的机器,systemd automount 可以减少开机卡顿(访问挂载点时再触发实际挂载):

fstab
192.168.10.20:/data/nfs/share /mnt/share nfs vers=4.1,hard,_netdev,x-systemd.automount,x-systemd.idle-timeout=600 0 0

业务进程启动时强依赖这个目录的情况下,automount 和依赖管理要一起看——进程起来时目录还没真正挂上,写入会落到本地空目录。

权限排查顺序

bash
id appdata                    # 客户端确认进程 UID/GID
mount | grep /mnt/share       # 挂载参数
ls -ldn /mnt/share            # 客户端看目录的数字 UID/GID
# 再到服务端
ls -ldn /data/nfs/share       # 服务端看真实目录的数字 UID/GID
现象方向
root 写入 Permission deniedroot_squash 生效,服务端匿名用户无权写
普通用户写失败客户端 UID/GID 和服务端目录属主不匹配
文件属主显示 nobody匿名映射或 idmapd 配置
某台能写另一台不能两台机器上的用户 UID/GID 不一致

需要所有客户端用户都按同一个身份写入时,用 all_squash

bash
/data/nfs/share 192.168.10.0/24(rw,sync,no_subtree_check,all_squash,anonuid=10001,anongid=10001)

这种写法会把所有客户端来的人映射到同一个 UID,审计上分不清是谁写的,但权限处理简单。适合内部脚本、统一任务这类场景。

性能和稳定性

NFS 性能受四层影响:服务端磁盘 IO → 服务端 CPU/网络 → 网络 RTT → 客户端挂载参数和应用 IO 模式。大量小文件、频繁 fsync、高并发随机写会放大 NFS 自身的瓶颈。

指标命令
服务端磁盘iostat -x 1
服务端网络sar -n DEV 1ss -tan
NFS 统计nfsstat -s(服务端)、nfsstat -c(客户端)
客户端 IOnfsiostat 1mountstats /mnt/share
目录容量df -hdf -i

安装工具:

bash
yum install -y nfs-utils sysstat
现象方向
延迟高服务端磁盘、网络 RTT、同步写、锁等待
小文件慢元数据操作多,目录项和 inode 压力大
写入抖动服务端 IO 打满、网络丢包、客户端重传
删除慢目录文件过多,服务端元数据压力

防火墙

NFSv4 核心端口是 2049:

bash
firewall-cmd --permanent --add-service=nfs
firewall-cmd --reload

NFSv3 还要关注 rpcbind(111)、mountd、statd、lockd——这些 RPC 服务默认端口不固定,排查时用 rpcinfo -p 看实际端口,再把它们一起开防火墙。

网络层确认:

bash
nc -vz 192.168.10.20 2049   # 客户端确认端口可达
exportfs -v                   # 服务端确认导出设置和客户端范围

常见故障

现象常见原因第一入口
access denied by serverexports 客户端范围不匹配、目录未导出exportfs -vshowmount -e
No such file or directory服务端路径写错、NFSv4 伪根路径不同/etc/exports、服务端目录
Permission deniedUID/GID、root_squash、目录权限idls -ln
客户端命令卡住hard mount 等待服务端恢复、网络中断dmesgnfsstat、服务端状态
写入很慢服务端磁盘、sync、网络延迟、小文件iostatnfsiostat
开机卡住fstab 网络挂载早于网络就绪_netdev、automount
文件属主异常idmap 或匿名映射ls -ln/etc/idmapd.conf

服务端排查命令:

bash
systemctl status nfs-server --no-pager
journalctl -u nfs-server -n 100 --no-pager
exportfs -v
showmount -e 127.0.0.1

客户端排查命令:

bash
mount | grep nfs
df -hT
dmesg | grep -i nfs | tail -50
nfsstat -c

hard 挂载在服务端异常时 IO 会阻塞直到恢复——不丢数据但进程看起来卡住。soft 会返回 IO error,进程看起来不卡但应用要能正确处理 IO 异常。数据库和写入类数据偏向 hard,临时只读类目录可评估 soft。

备份和高可用

NFS 是文件共享协议,不是备份。多客户端看的都是同一份数据,删了就是删了。

需求常见方案
防误删快照、rsync 多版本、对象存储备份
防单盘故障RAID、云盘快照、底层存储冗余
防单机故障双机 + VIP、NAS 替换、迁移到分布式文件系统
防容量打满磁盘水位告警、目录配额、保留策略
审计目录权限、应用日志、备份日志

简单备份脚本:

bash
#!/usr/bin/env bash
set -euo pipefail

src="/data/nfs/share/"
dst="/backup/nfs-share/$(date +%F)"
mkdir -p "${dst}"

# --delete 让目标端和源保持一致,适合版本目录已按日期隔离的场景
rsync -aH --numeric-ids --delete "${src}" "${dst}/"

# 保留 30 天
find /backup/nfs-share -mindepth 1 -maxdepth 1 -type d -mtime +30 -print -exec rm -rf {} \;

NFS 服务端恢复后还要确认客户端挂载和文件完整性。只把 nfs-server 拉起来就认为恢复完成,会漏掉客户端是否正常挂载、文件是否还在这些环节。