NFS 这个协议说老实话属于那种平时想不起来、真到用的时候又绕不开的东西。我在几台机器之间倒腾数据、给测试环境挂共享目录、给构建机做产物中转最后兜兜转转还是会回到 NFS 上——它简单、内核原生支持、不用装一堆额外组件配好之后几乎不用管。但每次隔几个月再配一遍总要在exports的权限参数、idmap的映射、防火墙端口这些地方卡一下尤其是加上 Kerberos 认证之后报错信息又特别含糊mount一句 Permission denied 能让人查半天。这篇就把我这些年配 NFS 服务端和客户端的完整流程捋一遍从最基础的无认证共享到带 Kerberos 的安全认证配置中间穿插那些文档里不写、但实际会踩的坑。适合两类人看一类是刚接触 Linux 文件共享、想快速把 NFS 跑起来的新手另一类是已经会用基础 NFS、但想在安全认证这块补齐短板的老手。基础部分我会讲清楚每个参数为什么这么设Kerberos 部分会把整个信任链条拆开讲保证你照着做能复现出了问题也知道往哪查。1. 先把 NFS 的版本和依赖关系理清楚很多人一上来就抄配置结果服务端起不来或者客户端挂不上根本原因是没搞清楚自己用的到底是 NFSv3 还是 NFSv4。这两个版本在架构上的差别挺大配置思路完全不一样先把这个理清楚后面能少走一大半弯路。1.1 NFSv3 和 NFSv4 到底差在哪NFSv3 是很多老系统的默认选择它的特点是依赖一堆辅助服务rpcbind负责端口映射rpc.mountd负责挂载授权rpc.statd负责锁状态还有rpc.lockd管文件锁。这些服务各自监听不同端口防火墙要放开一大片配起来琐碎。而且 v3 是无状态协议服务端重启之后客户端经常要重新挂载才能恢复正常。NFSv4 则把这些都收拢了它只用单个端口 2049把挂载、锁、状态管理全部整合进协议本身不再需要rpcbind那一套。对防火墙友好对跨网段场景也友好。更关键的是 v4 内置了 ACL 和更强的安全框架Kerberos 集成也是围绕 v4 设计的。所以如果你的环境不是特别老我建议直接上 NFSv4省心。不过有个现实问题某些老应用或者老内核只认 v3这时候服务端可以同时开 v3 和 v4让客户端自己协商。配置上就是exports里不写死版本服务端把两套都启起来。但要注意同时开两套意味着rpcbind也得留着防火墙规则要兼顾复杂度上去了。对比项NFSv3NFSv4依赖服务rpcbind、mountd、statd、lockd仅需 nfs-server端口多个动态端口固定 2049状态管理无状态重启需重挂有状态支持租约恢复安全框架依赖外部机制内置 RPCSEC_GSS防火墙友好度差好1.2 服务端要装哪些包不同发行版的包名有差异但核心就那几个。以常见的两类系统为例# Debian/Ubuntu 系 apt install nfs-kernel-server # RHEL/CentOS/Rocky 系 dnf install nfs-utils装完之后服务端核心是nfs-server这个服务v4 场景下启它就够了。如果还要支持 v3得额外确保rpcbind在跑。这里有个容易忽略的点nfs-server启动时会去读/etc/exports如果这个文件语法有问题服务直接起不来而且日志里不一定说得清楚。所以改完exports之后养成先跑exportfs -ra验证的习惯比直接重启服务安全。客户端这边v4 其实内核已经内置了挂载能力但为了用mount.nfs和排查工具还是建议装nfs-commonDebian 系或nfs-utilsRHEL 系。别小看这个有些精简系统里没有mount.nfsmount -t nfs会直接报 unknown filesystem type让人误以为是内核模块问题。1.3 内核模块和版本确认服务端需要内核加载nfsd模块客户端需要nfs模块。现代内核基本都是模块化加载一般不用手动modprobe但排查问题时确认一下有价值# 服务端确认 nfsd 已加载 lsmod | grep nfsd # 客户端确认 nfs 模块 lsmod | grep nfs # 查看支持的 NFS 版本 cat /proc/fs/nfsd/versions最后这条命令在服务端跑输出类似2 3 4 4.1 4.2加号表示启用。如果只想开 v4可以在/etc/nfs.conf新版本或/etc/sysconfig/nfs老版本里关掉低版本。我一般建议至少保留 v4.1 和 v4.2因为多路径和并行 I/O 这些特性在 4.1 之后才完善对性能有实际帮助。2. exports 文件的每一行都在决定权限边界/etc/exports是整个 NFS 服务端的权限中枢它的语法看着简单但每个选项背后都对应一套访问控制逻辑。我见过太多人抄了一行*全开结果共享目录被意外写入或者权限错乱。这一节把常用选项拆开讲让你知道每个参数在防什么。2.1 基础语法和共享目录定义一行典型的配置长这样/srv/share 192.168.1.0/24(rw,sync,no_subtree_check)结构是共享路径 允许的客户端 括号里的选项。客户端可以写单个 IP、网段、主机名也可以写*表示所有。多个客户端可以并列各自带各自的选项/srv/share 192.168.1.0/24(rw,sync) 10.0.0.5(ro,sync)这里第一个网段可读写第二个单机只读。注意客户端之间用空格分隔不要加逗号加了会解析失败。共享路径必须是服务端本地已存在的目录exports不会帮你创建。而且路径的父目录权限要允许nfsnobody或对应映射用户能进入否则即使exports放行了客户端挂载后也访问不了内容。这个坑很隐蔽因为挂载本身是成功的只是ls的时候报权限拒绝。2.2 rw、ro、sync、async 这些选项的实际含义rw和ro控制读写这个直观。但sync和async的取舍很多人没想明白。sync表示服务端在回复客户端写成功之前必须把数据真正落盘async则是先回成功、后台再刷盘。async性能好但服务端崩溃时可能丢数据。生产环境我强烈建议sync除非你明确知道这个共享是临时缓存、丢了无所谓。no_subtree_check这个选项值得单独说。默认情况下服务端会检查请求的文件是否在导出的子树内这个检查在文件被重命名或移动时会出问题而且有性能开销。现代内核里subtree_check基本是历史包袱直接no_subtree_check关掉更稳。对应的还有root_squash和no_root_squash前者把客户端的 root 映射成匿名用户后者保留 root 权限。除非是受控的信任环境否则别开no_root_squash等于把服务端的 root 权限交给了客户端。all_squash更彻底把所有用户都映射成匿名。适合公开只读共享。anonuid和anongid可以指定匿名映射到哪个 uid/gid配合all_squash用能控制匿名访问落到哪个本地账户上。2.3 一个我常用的生产级配置模板综合上面这些我一般会写成这样/srv/share 192.168.1.0/24(rw,sync,no_subtree_check,root_squash) /srv/public 192.168.1.0/24(ro,sync,no_subtree_check,all_squash,anonuid65534,anongid65534)第一行是内部读写共享root 被压制普通用户正常读写。第二行是公开只读所有访问都映射到nobody65534 通常是 nobody 的 uid。这样即使有人误操作也写不进公开目录。改完配置后别急着重启服务先验证exportfs -ra # 重新加载所有导出 exportfs -v # 查看当前生效的导出列表和选项exportfs -v的输出会把你配置的选项展开显示能直观看到每个共享实际生效的参数比翻配置文件靠谱。如果这里报错说明语法有问题根据提示改就行不会影响正在运行的服务。提示exports里客户端写主机名时服务端必须能反解这个主机名否则会匹配失败。跨网段或者 DNS 不完善的环境直接用 IP 或网段最稳。3. 客户端挂载参数选错比不挂还麻烦服务端配好了客户端挂载这一步看似一条命令的事但挂载参数的选择直接影响后续的读写行为、超时表现和故障恢复。我见过挂载成功但写入极慢的、断网后进程卡死的基本都是参数没调对。3.1 手动挂载的完整命令和参数解释一条我常用的挂载命令mount -t nfs -o vers4.2,rw,hard,timeo600,retrans2,rsize1048576,wsize1048576 192.168.1.10:/srv/share /mnt/share逐个说vers4.2明确指定版本避免协商到低版本hard表示服务端无响应时客户端持续重试而不是报错返回这对数据一致性重要但代价是进程可能卡住timeo600是重试超时单位是 0.1 秒600 就是 60 秒retrans2是重传次数rsize和wsize是读写块大小1MB 在现代网络上是比较合理的值太小影响吞吐太大在某些网络设备上会分片。hard和soft的取舍是个经典问题。soft在超时后返回错误进程不会卡死但可能读到不完整数据hard保证一致性但可能挂起。我的经验是数据库、构建产物这类不能出错的数据用hard临时日志、缓存类可以用soft配合较短的timeo。如果担心hard卡死可以加intr让信号能中断不过新内核里这个选项行为有变化得实测确认。3.2 开机自动挂载fstab 写法与坑写进/etc/fstab才能开机自动挂载192.168.1.10:/srv/share /mnt/share nfs vers4.2,rw,hard,timeo600,retrans2,_netdev 0 0这里_netdev很关键它告诉系统这个挂载依赖网络等网络就绪后再挂避免开机时网络还没起来导致挂载失败、进而卡住启动流程。少了这个选项某些系统上开机就会卡在挂载阶段。另一个坑是nofail。如果这个共享不是系统运行必需的加上nofail这样服务端不可达时系统仍能正常启动只是这个挂载点空着。生产环境里我基本都会加避免单点故障拖垮整台机器的启动。192.168.1.10:/srv/share /mnt/share nfs vers4.2,rw,hard,timeo600,retrans2,_netdev,nofail 0 0改完fstab后用mount -a测试别直接重启验证。mount -a会尝试挂载所有未挂载的条目报错能立刻看到。3.3 挂载后的权限验证和常见异常挂载成功后第一件事是验证权限是否符合预期# 查看挂载参数是否生效 mount | grep /mnt/share # 测试写入 touch /mnt/share/testfile rm /mnt/share/testfile # 查看实际生效的 uid/gid 映射 ls -ln /mnt/sharels -ln用数字显示 uid/gid能直观看出映射结果。如果发现文件属主变成了nobody或者一个奇怪的数字说明root_squash或all_squash在起作用这是预期行为不是故障。常见的异常里Permission denied 最典型原因可能是exports没放行这个客户端 IP、目录本地权限不对、或者 SELinux 拦截。SELinux 这块单独提一句RHEL 系默认开启NFS 共享目录需要正确的安全上下文否则即使传统权限全开也访问不了。用ls -Z看上下文必要时用chcon或semanage fcontext调整。这个坑在 Debian 系上遇不到换到 RHEL 系就容易中招。4. Kerberos 加持把 NFS 从内网裸奔拉到可信认证前面配的 NFS本质上靠 IP 和 uid 做信任内网里谁都能冒充。一旦共享跨了安全域或者合规上有要求就得上 Kerberos。这块是整个配置里最绕的部分因为涉及 KDC、服务主体、keytab、idmap 四五个环节任何一环没对上表现都是含糊的权限错误。我把它拆成一条完整的信任链来讲。4.1 Kerberos 认证 NFS 的整体信任链条先建立全局图景。Kerberos 场景下客户端访问 NFS 不再是我报个 uid 你就信而是客户端先用用户身份向 KDC 证明自己拿到一张服务票据service ticket然后带着这张票据访问 NFS 服务端服务端用自己 keytab 里的密钥验证票据真伪验证通过才放行。整个过程里双方都不需要直接信任对方的 IP 或 uid信任建立在 KDC 这个第三方上。这条链上有几个关键角色KDC发票据、NFS 服务端主体nfs/hostnameREALM、客户端用户主体userREALM、以及服务端的 keytab 文件存放服务端长期密钥。配置的核心就是把这几个角色的名字、密钥、映射关系全部对齐。4.2 KDC 侧创建服务主体和导出 keytab假设 realm 是EXAMPLE.LAB虚构示例NFS 服务端主机名是nfsserver.example.lab。在 KDC 上执行# 创建 NFS 服务主体 kadmin.local -q addprinc -randkey nfs/nfsserver.example.labEXAMPLE.LAB # 导出到 keytab kadmin.local -q ktadd -k /etc/krb5.keytab nfs/nfsserver.example.labEXAMPLE.LAB-randkey表示随机生成密钥不需要人工记密码。导出的 keytab 要安全地传到 NFS 服务端的/etc/krb5.keytab权限设成600属主 root。这个文件就是服务端的身份证泄露了等于别人能冒充服务端务必管好。这里有个细节主体名里的主机名必须和客户端访问时用的名字一致。如果客户端用 IP 访问而主体是按主机名建的票据就对不上。所以 Kerberos 场景下客户端挂载必须用主机名且这个主机名要能正反解。DNS 不完善的环境得在/etc/hosts里把映射写死。4.3 服务端配置 seckrb5 和 idmap 映射服务端的exports要加上安全模式/srv/secure 192.168.1.0/24(rw,sync,no_subtree_check,seckrb5p)sec有四个级别sys默认无认证、krb5认证、krb5i认证加完整性校验、krb5p认证加加密。krb5p最安全但性能开销最大因为每个数据包都要加密解密。内网可信环境用krb5就够跨不可信网络再上krb5p。我一般建议先配krb5跑通确认整条链没问题再按需升级到krb5i或krb5p因为加密级别一上去排查难度也上去了。idmap 是另一个关键。Kerberos 票据里带的是userREALM这种名字但文件系统只认数字 uid/gididmapd负责把名字翻译成数字。服务端和客户端的/etc/idmapd.conf里Domain必须设成同一个值通常就是 realm 的小写形式否则映射失败所有文件都显示成nobody。[General] Domain example.lab [Mapping] Nobody-User nobody Nobody-Group nogroup改完idmapd.conf要重启nfs-idmapd服务。这个服务在 v4 场景下是必需的很多人配完 Kerberos 发现文件属主全是 nobody八成就是这里 Domain 不一致或者服务没重启。4.4 客户端拿到票据再挂载客户端这边先确保/etc/krb5.conf指向正确的 KDC然后用用户身份拿票据kinit userEXAMPLE.LAB klist # 确认票据已获取拿到票据后再挂载挂载时指定安全模式mount -t nfs -o vers4.2,seckrb5,hard nfsserver.example.lab:/srv/secure /mnt/secure注意这里用的是主机名而不是 IP。挂载成功后访问文件时客户端会自动用票据向服务端认证。如果票据过期访问会失败重新kinit即可。这也是 Kerberos 场景和普通 NFS 的一个体验差异普通 NFS 挂上就一直能用Kerberos 场景下票据是有生命周期的长时间运行的进程要注意票据续期。4.5 Kerberos 配置里最容易翻车的几个点我把踩过的坑列一下基本都是配置看着都对、就是不工作的类型第一时间不同步。Kerberos 对时间极其敏感客户端和 KDC 的时间偏差超过默认 5 分钟票据直接被拒。所有相关机器都要配好时间同步这是前提不是可选项。第二keytab 里的主体名和exports里隐含的服务名不匹配。服务端验证票据时用的是nfs/hostname这个主体如果 keytab 里建的是别的名字验证必然失败。用klist -k /etc/krb5.keytab确认 keytab 内容。第三DNS 正反解不一致。前面提过客户端用主机名访问服务端主体也按主机名建中间任何一环解析对不上就断链。getent hosts nfsserver.example.lab和host nfsserver.example.lab都确认一遍。第四idmap 的 Domain 大小写。idmapd.conf里 Domain 一般用小写而 realm 是大写两者不是简单的大小写关系要按实际配置对齐。映射不上时先看/var/log/syslog或journalctl -u nfs-idmapd里的映射日志。第五防火墙只放了 2049 但没放 KDC 的 88 端口。客户端要能访问 KDC 才能拿票据这个端口不通kinit就失败但报错信息可能只说是无法联系 KDC容易误判成 KDC 没起。故障现象最可能原因排查命令kinit 失败时间偏差 / KDC 不可达date、nc -vz kdc 88挂载报 Permission denied主体名不匹配 / keytab 缺失klist -k /etc/krb5.keytab文件属主全是 nobodyidmap Domain 不一致cat /etc/idmapd.conf票据验证失败DNS 正反解不一致getent hosts host5. 性能调优和日常运维里那些值得记下来的细节配置跑通只是开始真正让 NFS 稳定好用还得在性能参数和日常维护上花点心思。这一节聊几个我实际调过的点和维护习惯。5.1 rsize/wsize 和网络环境的匹配rsize和wsize不是越大越好。1MB 在千兆内网是甜点值但如果是跨广域网或者经过某些老交换机大块会导致分片和重传反而慢。判断方法很简单挂载后跑一次大文件拷贝用nfsstat -c看重传率和 RPC 统计重传率高就往下调比如降到 256KB 或 128KB 再测。这个调优没有万能值得结合自己的网络实测。另外v4.1 之后支持多路径nconnect挂载选项在有多网卡或者高带宽场景下能显著提升吞吐mount -t nfs -o vers4.2,nconnect4 ...nconnect4表示建立 4 条连接并行传输。这个选项对单流带宽受限的场景效果明显但要注意服务端和网络设备是否支持盲目开高值可能适得其反。5.2 服务端线程数和缓存服务端的nfsd线程数默认值在负载高时可能不够。查看当前值cat /proc/fs/nfsd/threads调整可以在/etc/nfs.conf里设[nfsd] threads或者在运行时写/proc/fs/nfsd/threads。线程数不是越多越好一般按并发客户端数量估算每个活跃客户端配 8 到 16 个线程比较合理超过 CPU 核数太多反而增加上下文切换开销。5.3 日常巡检要看哪几个指标我习惯定期看这几个nfsstat -s看服务端 RPC 统计重点看badcalls和重传nfsiostat看每个挂载点的 I/O 延迟showmount -e确认导出列表没被意外改动。这几个命令组合起来基本能覆盖大部分潜在问题。特别是nfsiostat里的平均 RPC 延迟一旦持续升高往往是网络或服务端负载出了问题早发现早处理。还有个小习惯每次改完exports或 Kerberos 相关配置先在测试客户端上完整走一遍挂载、读写、卸载确认无误再推到生产。NFS 的配置错误有时候不会立刻暴露等到业务跑起来才发现权限不对排查成本就高了。我个人在实际操作中的体会是NFS 这东西的复杂度不在配置本身而在环境依赖——DNS、时间同步、idmap、防火墙任何一个环节的疏漏都会以权限错误的形式表现出来让人误以为是 NFS 配置的问题。所以配 Kerberos 版 NFS 时我现在的习惯是先把这些外围依赖逐项确认一遍再动 NFS 配置能省掉大量来回排查的时间。
阅读完成 · 觉得有帮助?