引言
多台机器共享同一份文件,最简单的方式是「网络文件系统」:服务端导出目录,客户端把它挂载成本地路径,读写就像本地文件。Linux 世界有两大阵营——NFS(Unix 原生,类 Unix 环境首选)与 CIFS/SMB(Windows 原生,Samba 让 Linux 也能提供服务)。选错协议或配错挂载选项,轻则性能腰斩,重则出现「文件明明写了却读不到」「客户端卡死无法卸载」的诡异故障。
本文从协议演进讲起,完整覆盖 NFS 服务端导出与客户端挂载、v4 的伪文件系统与 idmap、Samba 共享与 CIFS 挂载、性能调优与排错,以及安全加固。目标是让你既能搭起一套可靠的文件共享,也能在出问题时快速定位。
前置:网络配置与连通性排查见 Linux 网络配置与排查 ,权限与 ACL 见 Linux 用户权限与安全加固 ,防火墙放行见 Linux 防火墙与 nftables 。
1. 网络文件系统概览:NFS vs CIFS/SMB
两者解决同一个问题,但设计哲学与适用场景不同:
| 维度 | NFS | CIFS/SMB |
|---|---|---|
| 出身 | Sun,Unix 原生 | Microsoft,Windows 原生 |
| 认证 | AUTH_SYS(UID/GID)或 Kerberos | 用户/密码、域、Kerberos |
| 锁 | NLM(v3)/ 内建(v4) | 内建 |
| 跨平台 | Linux↔Unix 最佳 | Windows↔Linux 互通最佳 |
| 典型端口 | 2049(v4 单端口) | 445(SMB3) |
| 适用 | 集群共享、HPC、容器 PV | 办公共享、Windows 互操作 |
选择直觉:
纯 Linux 集群 / Kubernetes PV / HPC → NFS
需要和 Windows 客户端互通 / 域认证 → CIFS(Samba)
两者都要 → Samba 同时提供 SMB 与 NFS(或各跑一个)
心智:NFS 是「Unix 语义的网络磁盘」,CIFS 是「Windows 语义的网络共享」。语义差异体现在权限、锁、大小写敏感性上,混用时要特别小心。
2. NFS 版本演进:v3 到 v4.2
# 查服务端与客户端支持的版本
nfsstat -s # 服务端统计
nfsstat -c # 客户端统计
cat /proc/fs/nfsd/versions # 服务端启用的版本(如 +4.2 +4.1 +4 +3 +2)
| 版本 | 关键特性 | 端口 |
|---|---|---|
| v3 | 无状态、需 NLM 锁、多端口 | 2049 + portmap/rpcbind |
| v4.0 | 有状态、单端口 2049、内建锁、伪文件系统 | 2049 |
| v4.1 | pNFS 并行访问、会话与 trunking | 2049 |
| v4.2 | server-side copy、稀疏文件、fallocate | 2049 |
v4 的单端口特性极大简化了防火墙:v3 需要放行 2049 加 rpcbind(111)与一堆动态端口,v4 只需 2049。
# 只启用 v4.2(服务端,/etc/nfs.conf 或发行版对应文件)
# [nfsd]
# vers4.2=y
# vers3=n
记忆:新部署一律优先 NFSv4.1/4.2——单端口好放行、内建锁、支持 Kerberos,且避免了 v3 的 rpcbind 与 NLM 一堆端口。
3. 搭建 NFS 服务端:exports 与权限
# 安装
sudo apt install nfs-kernel-server # Debian/Ubuntu
sudo dnf install nfs-utils # RHEL 系
# /etc/exports
/data/shared 192.168.1.0/24(rw,sync,no_subtree_check)
/data/ro *(ro,root_squash)
/home client1.example.com(rw,async,no_root_squash)
| 选项 | 含义 |
|---|---|
rw / ro | 读写 / 只读 |
sync / async | 同步落盘(安全)/ 异步(快,可能丢数据) |
root_squash | 客户端 root 映射为匿名用户(默认,安全) |
no_root_squash | 保留 root 权限(危险,仅信任网络用) |
all_squash | 所有用户都映射为匿名 |
no_subtree_check | 关闭子树检查(提升兼容与性能) |
noacl / acl | 是否支持 POSIX ACL |
# 应用导出并查看
sudo exportfs -ra # 重新导出全部
sudo exportfs -v # 查看当前导出与选项
sudo systemctl enable --now nfs-server
# 放行防火墙(v4 单端口)
sudo firewall-cmd --add-service=nfs --permanent
sudo firewall-cmd --reload
权限的关键:NFS 默认用「客户端上报的 UID/GID」做鉴权(AUTH_SYS)
→ 客户端 root 被 root_squash 映射为 nobody
→ 要让共享目录可写,需保证 UID/GID 在两端一致,或调 squash 策略
铁律:
no_root_squash只在对端完全可信时使用。它允许客户端 root 在共享目录里为所欲为,是 NFS 被入侵后横向移动的常见跳板。
4. 挂载 NFS 客户端与 mount 选项调优
# 查看服务端导出
showmount -e nfs-server
# 挂载
sudo mount -t nfs4 nfs-server:/data/shared /mnt/shared
# 写入 fstab
echo "nfs-server:/data/shared /mnt/shared nfs4 rw,hard,rsize=1048576,wsize=1048576,_netdev 0 0" | sudo tee -a /etc/fstab
| 选项 | 作用 | 建议 |
|---|---|---|
hard / soft | 服务端不可达时无限重试 / 超时返回错误 | 数据盘用 hard,避免静默丢数据 |
intr | 允许中断 hard 挂载的等待 | 老内核需要,新版默认 |
rsize / wsize | 单次读写块大小 | 1MB(1048576)常最优 |
timeo | 超时(单位 0.1s) | 网络差可调大 |
retrans | 重传次数 | 配合 timeo |
_netdev | 等网络就绪再挂载 | fstab 必加 |
nconnect | 单挂载点的 TCP 连接数 | v4.1+ 可设 4~16 提升吞吐 |
noatime | 不更新访问时间 | 减少写 |
# nconnect 提升多流并发吞吐(需 v4.1+)
sudo mount -t nfs4 -o nconnect=8 nfs-server:/data/shared /mnt/shared
心法:
hard+_netdev是生产 NFS 挂载的底线。soft会在服务端短暂不可达时让应用收到 I/O 错误,可能造成静默数据损坏;_netdev保证开机时网络就绪后才挂载,避免启动卡死。
5. NFSv4:伪文件系统、idmap 与 Kerberos
v4 用伪文件系统把服务端所有导出组织成一棵树,客户端挂载根 / 就能看到全部:
服务端伪文件系统(/etc/exports 里的 fsid 决定挂载点):
/ ← 伪根
├─ data/shared ← 对应 /data/shared
└─ home ← 对应 /home
客户端:mount -t nfs4 nfs-server:/ /mnt
idmap 解决 v4 的「user@domain 字符串身份」与本地 UID/GID 的映射:
# /etc/idmapd.conf(两端一致)
# [General]
# Domain = example.com
# [Mapping]
# Nobody-User = nobody
# Nobody-Group = nogroup
sudo systemctl enable --now nfs-idmapd
# 检查映射
nfsidmap -l
**Kerberos(sec=krb5)**让 NFS 从「信任 UID」升级为「密码学认证」:
# 挂载时指定安全级别
sudo mount -t nfs4 -o sec=krb5p nfs-server:/data/shared /mnt
| sec 级别 | 认证 | 完整性 | 加密 |
|---|---|---|---|
sys | AUTH_SYS | 无 | 无 |
krb5 | Kerberos | 无 | 无 |
krb5i | Kerberos | 有 | 无 |
krb5p | Kerberos | 有 | 有(性能最低) |
记忆:
sys信任客户端自报身份,krb5p全加密最安全也最慢。跨不可信网络必须上 Kerberos;内网可信环境sys才可接受。
6. CIFS/SMB 服务端:Samba 配置
sudo apt install samba # 或 dnf install samba
# /etc/samba/smb.conf
[global]
workgroup = WORKGROUP
server string = File Server
security = user # 用户级认证
map to guest = bad user
[shared]
path = /srv/shared
browseable = yes
writable = yes
valid users = alice, bob
create mask = 0644
directory mask = 0755
force group = sharedgrp
# 创建 Samba 用户(需先有系统用户)
sudo useradd -M -s /sbin/nologin alice
sudo smbpasswd -a alice # 设置 SMB 密码
sudo testparm # 校验配置语法
sudo systemctl enable --now smbd nmbd
# 放行防火墙
sudo firewall-cmd --add-service=samba --permanent && sudo firewall-cmd --reload
# 列出共享(本机)
smbclient -L localhost -U alice
| 段 | 作用 |
|---|---|
[global] | 全局设置(认证方式、工作组) |
[共享名] | 每个共享目录一段 |
valid users | 允许访问的用户 |
writable / read only | 写权限 |
create mask / directory mask | 新建文件/目录权限 |
心法:Samba 用户与系统用户是两套密码——
smbpasswd管 SMB 认证,系统密码管本地登录。用-M -s /sbin/nologin建「只用于 SMB、不能本地登录」的账号最安全。
7. 挂载 CIFS 客户端与凭据管理
# 交互式挂载
sudo mount -t cifs //server/shared /mnt/shared -o username=alice,uid=1000,gid=1000
# 用凭据文件(避免密码出现在命令行/ps 里)
sudo tee /root/.smbcred >/dev/null <<'EOF'
username=alice
password=secret
domain=WORKGROUP
EOF
sudo chmod 600 /root/.smbcred
sudo mount -t cifs //server/shared /mnt/shared -o credentials=/root/.smbcred,uid=1000,gid=1000,vers=3.1.1
# /etc/fstab
//server/shared /mnt/shared cifs credentials=/root/.smbcred,uid=1000,gid=1000,vers=3.1.1,_netdev,nofail 0 0
| 选项 | 作用 |
|---|---|
credentials= | 从文件读账号密码 |
uid= / gid= | 强制挂载点归属(SMB 无 Unix UID) |
vers=3.1.1 | 协议版本(避免协商到过老的 SMB1) |
iocharset=utf8 | 中文文件名 |
nofail | 挂载失败不阻塞开机 |
铁律:CIFS 挂载必须显式指定
uid/gid——SMB 协议不带 Unix 身份,不指定的话所有文件都会归 root,普通用户无法写。同时锁死vers=3.1.1,杜绝降级到不安全的 SMB1。
8. 性能调优与排错
# 性能:加大 rsize/wsize 与 nconnect
mount -t nfs4 -o rsize=1048576,wsize=1048576,nconnect=8 server:/data /mnt
# 用 dd 粗测吞吐
dd if=/dev/zero of=/mnt/test bs=1M count=1024 oflag=direct
dd if=/mnt/test of=/dev/null bs=1M iflag=direct
# 看 RPC 统计与重传
nfsstat -c
nfsiostat 1 5 # 每挂载点的 IO 延迟与吞吐(sysstat 包)
# 排错:连不上先分层确认
ping nfs-server # 1. 网络通不通
rpcinfo -p nfs-server # 2. v3 的 RPC 服务是否注册
showmount -e nfs-server # 3. 导出是否可见
sudo mount -v -t nfs4 ... /mnt # 4. 详细挂载日志
dmesg | tail -30 # 5. 内核报错
journalctl -u nfs-server # 6. 服务端日志
| 现象 | 原因 | 对策 |
|---|---|---|
mount: access denied | 导出未包含该客户端/权限不足 | 检查 /etc/exports 与 exportfs -v |
| 写文件后读不到 | async 缓存 + 多客户端缓存 | 改 sync 或加 actimeo=0 |
| 挂载点卡死无法卸载 | hard 挂载 + 服务端失联 | umount -f 或 -l(lazy) |
| CIFS 中文乱码 | 缺 iocharset | 加 iocharset=utf8 |
| 吞吐低 | rsize/wsize 太小 | 设 1MB + nconnect |
| 文件权限全 root | CIFS 未设 uid/gid | 加 uid=/gid= |
心法:NFS 排错按「网络 → RPC → 导出 → 挂载 → 日志」逐层确认。大多数「挂不上」是导出范围或防火墙问题,而非协议本身。
9. 安全与访问控制
# 1. 限制导出范围,绝不用 *(rw)
# /etc/exports: /data 192.168.1.0/24(rw,sync,root_squash,no_subtree_check)
# 2. 用 Kerberos 替代 AUTH_SYS
mount -t nfs4 -o sec=krb5p server:/data /mnt
# 3. 只暴露必要端口(v4 仅 2049)
sudo nft add rule inet filter input tcp dport 2049 ip saddr 192.168.1.0/24 accept
# 4. Samba 锁死协议版本,禁用 SMB1
# smb.conf [global]: server min protocol = SMB3
| 加固项 | 做法 |
|---|---|
| 最小导出范围 | 用 CIDR 精确到子网,禁用 * |
| root 保护 | 保持 root_squash,禁 no_root_squash |
| 加密认证 | NFS 用 sec=krb5p,SMB 用 SMB3 加密 |
| 协议版本 | 禁用 NFSv2 与 SMB1 |
| 防火墙 | 仅放行可信子网到 2049/445 |
| 审计 | 记录挂载与访问日志 |
# 查看谁在挂载、谁在访问(服务端)
showmount -a
cat /proc/fs/nfsd/clients/*/info 2>/dev/null
铁律:永远不要用
*(rw,no_root_squash)。这是 NFS 最经典的高危配置,等于把服务端的 root 权限开放给整个网络;确需写权限时用「限定子网 + root_squash + UID 对齐」。
10. 速查表
| 需求 | 命令 |
|---|---|
| 查导出 | showmount -e server |
| 重载导出 | exportfs -ra |
| 挂 NFSv4 | mount -t nfs4 server:/data /mnt |
| 高性能挂载 | -o rsize=1048576,wsize=1048576,nconnect=8 |
| 安全挂载 | -o sec=krb5p |
| 强制卸载 | umount -f /mnt 或 -l |
| 看 RPC 统计 | nfsstat -c |
| 看挂载点性能 | nfsiostat 1 |
| 校验 Samba | testparm |
| 加 SMB 用户 | smbpasswd -a alice |
| 挂 CIFS | mount -t cifs //s/shared /mnt -o credentials=...,uid=,gid= |
| 列 SMB 共享 | smbclient -L server -U user |
一句话记忆:NFS 是 Unix 语义网络磁盘、CIFS 是 Windows 语义共享;NFS 服务端 exports 控权限、客户端用 hard+_netdev 保可靠、nconnect+大 rsize/wsize 提性能、sec=krb5p 保安全;Samba 用 smbpasswd 管 SMB 用户、CIFS 挂载必须锁 vers=3.1.1 并指定 uid/gid——永远别开 no_root_squash 与 *(rw)。
延伸阅读
- Linux 网络配置与排查 — 连通性与路由排查
- Linux 用户权限与安全加固 — UID/GID 与 ACL 对齐
- Linux 防火墙与 nftables — 精确放行 2049/445
- Linux 安全加固实战 — 服务最小化与访问控制
- 网络专题 — TCP/IP 与 RPC 协议栈
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。