Appearance
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.1 或 4.2 比让客户端和服务端自动协商更可控。老 NAS 可能只支持 v3,此时要把 rpcbind、mountd、statd 的端口和防火墙规则一起记录——v3 不是单端口协议,仅开 2049 不够。
服务端部署
示例环境:
| 主机 | IP | 角色 |
|---|---|---|
nfs01 | 192.168.10.20 | 服务端 |
app01 | 192.168.10.31 | 客户端 |
app02 | 192.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,不是用户名字符串。app01 上 appdata 是 UID 1001,nfs01 上 appdata 是 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/shareUbuntu/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=600 | RPC 超时,单位 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 denied | root_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 1、ss -tan |
| NFS 统计 | nfsstat -s(服务端)、nfsstat -c(客户端) |
| 客户端 IO | nfsiostat 1、mountstats /mnt/share |
| 目录容量 | df -h、df -i |
安装工具:
bash
yum install -y nfs-utils sysstat| 现象 | 方向 |
|---|---|
| 延迟高 | 服务端磁盘、网络 RTT、同步写、锁等待 |
| 小文件慢 | 元数据操作多,目录项和 inode 压力大 |
| 写入抖动 | 服务端 IO 打满、网络丢包、客户端重传 |
| 删除慢 | 目录文件过多,服务端元数据压力 |
防火墙
NFSv4 核心端口是 2049:
bash
firewall-cmd --permanent --add-service=nfs
firewall-cmd --reloadNFSv3 还要关注 rpcbind(111)、mountd、statd、lockd——这些 RPC 服务默认端口不固定,排查时用 rpcinfo -p 看实际端口,再把它们一起开防火墙。
网络层确认:
bash
nc -vz 192.168.10.20 2049 # 客户端确认端口可达
exportfs -v # 服务端确认导出设置和客户端范围常见故障
| 现象 | 常见原因 | 第一入口 |
|---|---|---|
access denied by server | exports 客户端范围不匹配、目录未导出 | exportfs -v、showmount -e |
No such file or directory | 服务端路径写错、NFSv4 伪根路径不同 | /etc/exports、服务端目录 |
Permission denied | UID/GID、root_squash、目录权限 | id、ls -ln |
| 客户端命令卡住 | hard mount 等待服务端恢复、网络中断 | dmesg、nfsstat、服务端状态 |
| 写入很慢 | 服务端磁盘、sync、网络延迟、小文件 | iostat、nfsiostat |
| 开机卡住 | 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 -chard 挂载在服务端异常时 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 拉起来就认为恢复完成,会漏掉客户端是否正常挂载、文件是否还在这些环节。