Appearance
NFS Client Mount 疑難排解與最佳實踐
Linux 主機作為 NFS client 時的完整排查流程:mount 驗證四維度、fstab 選項深度解析、umount/remount 正確操作,以及 HA failover 期間的行為說明。
概述
NFS client 掛載的常見誤判是「ls 看起來是空的就認為 mount 失敗」——實際上 NFSv4 剛建立 session 時存在短暫的 dentry cache race,幾秒後重試就正常。診斷 mount 是否成功,需要交叉驗證 mount table、stat device number、nfsstat 協商資訊,以及實際 IO 四個維度,任一單一訊號都可能誤判。
fstab 的選項設計同樣有許多細節:_netdev 告訴 systemd 等網路就緒後才 mount、nofail 讓開機不因 NFS 失敗而卡住、hard 確保資料安全(預設值,不應改為 soft)。timeo 的單位是 0.1 秒而非秒,許多人因此設了過於激進的值。NFS remount 不允許修改連線相關參數,套用新 fstab 必須走 umount + mount 流程。
本文件處理任何 Linux 主機作為 NFS client 時遇到的問題。NFS server 本身(HA cluster)的故障排查見 DRBD + Pacemaker NFS HA Cluster 完整復原 Runbook。
核心內容
Mount 成功驗證四維度
單一訊號容易誤判,建議交叉比對:
bash
# 維度 1:mount table 有這筆
mount | grep /mnt/nfs_share
findmnt /mnt/nfs_share
# 維度 2:stat 的 device number 與 rootfs 不同
stat /mnt/nfs_share | grep Device
stat / | grep Device
# 兩個 Device 值必須不一樣
# 維度 3:NFS 層協商資訊
nfsstat -m | grep -A5 /mnt/nfs_share
# 應看到 vers=4.2, proto=tcp, addr=10.248.36.109
# 維度 4:實際 IO
touch /mnt/nfs_share/.probe_$$ && rm /mnt/nfs_share/.probe_$$
echo "IO works: $?"四個都通過 = mount 百分百成功。三個通過一個可疑 = 可能是 dentry cache race,等幾秒再試。
Mount 後看起來是空的 — 診斷流程
START
│
▼
mount | grep <mount-point> + findmnt <mount-point>
│
├── 都看不到 → mount 沒成功,查 dmesg + mount 指令的 exit code(見下節)
│
└── 看得到 NFS 條目 → mount 成功,繼續
│
▼
stat <mount-point> vs stat / 比對 Device 欄位
│
├── Device 相同 → mount 雖在 table 但未真正生效(kernel bug / namespace 問題)
│
└── Device 不同 → mount 生效,繼續
│
▼
ls 是空的?
├── a) NFSv4 dentry cache benign race → 等 5 秒重試
├── b) server 端本身就是空的 → 去 server 端 ls 確認
└── c) NFSv4 pseudo-root 設定問題(本環境不適用,僅供參考)Mount 真的沒成功的診斷
bash
# 重新執行 mount 並看 exit code
sudo mount -v 10.248.36.109:/mnt/nfs_share /mnt/nfs_share
echo "exit: $?"
# kernel 層錯誤
sudo dmesg -T | grep -iE 'nfs|rpc' | tail -20
# 網路可達性
ping -c 3 10.248.36.109
nc -zv 10.248.36.109 2049 # NFSv4 只需 tcp:2049
# server export 設定
showmount -e 10.248.36.109
ip -br addr show | grep UP常見失敗原因:
| 症狀 | 根因 | 修復 |
|---|---|---|
access denied by server | client IP 不在 exportfs clientspec | server 端改 /etc/exports + exportfs -r |
No such file or directory | server 路徑寫錯,或 server 端 fs 未 mount | 確認 server 端 ls /mnt/nfs_share 有內容 |
Connection refused | VIP 未起來,或 nfs-server 未啟動 | 回 HA cluster runbook |
operation not permitted | 缺 sudo | sudo mount ... |
| 卡住不回應 | firewall 擋、或 VIP 正在 failover | tcpdump -i any host 10.248.36.109 看封包 |
fstab 選項深度解析
_netdev(極重要)
告訴 systemd 等 network-online.target 完成後才 mount。沒加的話,systemd 可能在網路就緒前嘗試 mount,失敗後被 nofail 靜默蓋過,開機看起來正常但 mount 點實際是空的。
驗證:
bash
systemctl show mnt-nfs_share.mount -p After -p Wants | grep network
# 應看到 network-online.targetnofail
Mount 失敗時不阻塞 systemd boot process。幾乎一定要加:NFS server 暫時不可用時,沒有此選項會讓開機卡在 90 秒 timeout。
Trade-off:mount 失敗會被靜默藏起來,需靠監控才發現。
hard vs soft(預設 hard)
| 選項 | 語意 | 適合場景 |
|---|---|---|
hard | server 不回應時無限重試,process 會 hang 住 | Production,資料不能丟 |
soft | retrans 次數用完後放棄,回 I/O error 給 application | 監控 / 非關鍵 read |
強烈建議用 hard(也是預設值)。soft 在 server 短暫故障時會直接截斷正在寫入的檔案。
timeo(單位:0.1 秒,不是秒)
初次 RPC 等待回應的 timeout。預設 600(即 60 秒)。
- 值太小(如 30 = 3 秒):網路短暫抖動就會多送 RPC
- 值太大(600,預設):容忍抖動,但 server 真死時要等較久
NFS 會指數退避:第一次 timeo、第二次 2×timeo…上限 60 秒。推薦 150(15 秒)。
retrans
soft mount 下:用完後放棄並回 I/O error。hard mount 下:每過 retrans 次就在 syslog 印一次警告,無法讓 hard mount 放棄。預設 2。改大只是降低 warning 頻率。
noatime
不更新 file access time。每次讀檔省一個 write RPC,對 read-heavy 或大量小檔案場景效益顯著。建議加,除非應用確實依賴 atime(罕見)。
Server Failover 期間的行為
NFS server 是 HA cluster,VIP 在 master2/master3 間遷移。Failover 期間(約 30–60 秒):
- Hard mount client 會卡住所有 IO(符合預期,資料安全)
- VIP 遷移完畢後,IO 自動 resume,不需要 remount
- 正在寫入的檔案可能看到瞬間 EIO,檔案狀態需 application 層保證
- 不會有資料丟失,但 read-intensive workload 建議加 retry 邏輯
NFSv3 vs NFSv4 差異重點
本環境協商到 NFSv4.2,但舊版 K8s CSI driver 可能用 NFSv3:
| 項目 | NFSv3 | NFSv4 |
|---|---|---|
| Ports | 2049 + portmap/111 + 動態 ports | 只有 tcp/2049 |
| 有狀態 | 無狀態(stateless) | 有狀態(stateful) |
| Lock 協議 | NLM(獨立) | 內建 |
| Auth | AUTH_SYS(UID/GID 直接送) | 支援 Kerberos |
| Delegation | 無 | 有(client 可更積極快取) |
關鍵要點
- 判斷 mount 成功要用四維度交叉驗證,不要只靠
ls的輸出 timeo單位是 0.1 秒,不是秒;預設 600 = 60 秒,不是 600 秒- NFS remount 無法修改連線相關參數(timeo、retrans、vers 等),必須 umount + mount
_netdev+nofail是每個網路 mount 的基本配備,缺一不可hardmount 在 HA failover 期間表現為 IO hang(正確的安全行為),不是故障
部署設定參考
環境參數
| 項目 | 值 |
|---|---|
| NFS server(HA cluster VIP) | 10.248.36.109 |
| Export 路徑 | /mnt/nfs_share |
| Export policy | clientspec=10.248.36.0/24, mountpoint, no_root_squash, sync |
| 協商版本 | NFSv4.2(server 支援,預設協商最高版本) |
| NFS port | tcp/2049(NFSv4 only) |
推薦 fstab 配置
fstab
10.248.36.109:/mnt/nfs_share /mnt/nfs_share nfs _netdev,nofail,noatime,timeo=150,retrans=3 0 0_netdev+nofail:開機安全noatime:省流量(每次 read 不更新 atime)timeo=150(15 秒):比預設 60 秒敏感,但不激進retrans=3:hard mount 下只影響 syslog 頻率,適度即可- 不指定
vers/proto:讓協商決定(目前會是 NFSv4.2 / tcp)
套用新 fstab 配置的正確流程
NFS remount 不允許修改連線相關參數,套用新 fstab 必須走完整的 umount + mount:
bash
# 第 0 步:先 cd 離開 mount point(否則 umount 會失敗)
cd ~
# 第 1 步:確認沒有 process 在用
sudo fuser -vm /mnt/nfs_share
# 若有列出 PID,決定要 kill 還是等它結束
# 第 2 步:umount
sudo umount /mnt/nfs_share
# 若出現 "target is busy",用 lazy umount:
# sudo umount -l /mnt/nfs_share
# 第 3 步:重新 mount(會讀取 fstab 最新內容)
sudo mount /mnt/nfs_share
# 第 4 步:驗證
findmnt /mnt/nfs_share
nfsstat -m | grep -A5 nfs_share # 確認 timeo/retrans 是新值Busy 時的處理
bash
# 選項 A:查出誰在用,kill 或讓它放掉
sudo fuser -vm /mnt/nfs_share
sudo lsof +D /mnt/nfs_share 2>/dev/null | head
# 選項 B:Lazy umount(通常夠用,對 NFS 安全)
sudo umount -l /mnt/nfs_share
# 現有 process 繼續用舊 mount 直到關檔,新存取走新 mount
# 選項 C:Force(最後手段,可能造成正在寫入的資料不一致)
sudo umount -f /mnt/nfs_share完整驗證 Checklist
套用新 fstab 後逐項確認:
- [ ]
findmnt /mnt/nfs_share有輸出 - [ ]
stat /mnt/nfs_share的 Device 與stat /不同 - [ ]
nfsstat -m | grep -A5 nfs_share顯示新選項(timeo=150, retrans=3, noatime) - [ ]
systemctl show mnt-nfs_share.mount -p After輸出包含network-online.target - [ ]
ls /mnt/nfs_share | head看得到內容 - [ ]
touch /mnt/nfs_share/.probe_$$ && rm /mnt/nfs_share/.probe_$$IO 可寫入 - [ ] (可選)重開機一次,確認開機後 mount 自動生效
指令速查
bash
# 查狀態
mount | grep <path>
findmnt <path> # 結構化輸出
nfsstat -m # NFS client 協商資訊
nfsstat -c # NFS client RPC 統計
stat <path> # Device number 對比
systemctl list-units --type=mount
systemctl show <unit>.mount
# 操作
sudo mount <path> # 根據 fstab mount
sudo umount <path>
sudo umount -l <path> # Lazy umount
sudo mount -a # mount 所有 fstab 中 auto 項目
sudo mount --fake <path> # 不實際 mount,只驗證語法
# 除錯
sudo dmesg -T | grep -iE 'nfs|rpc' | tail
sudo fuser -vm <path> # 誰在用這個 mount
sudo lsof +D <path>
showmount -e <server> # Server export 清單
nc -zv <server> 2049 # 測試 tcp/2049 通不通常見陷阱
fstab mount unit 名稱規則
systemd 根據 mount point 產生 unit 名稱,規則是把路徑的 / 換成 -:
| Mount Point | Unit Name |
|---|---|
/mnt/nfs_share | mnt-nfs_share.mount |
/data/nfs | data-nfs.mount |
systemctl 指令要用 unit name,不是路徑。
寫入 /mnt/nfs_share 根目錄的風險
根目錄下有 K8s PV 目錄(swiss_simulation、wimap_projects、bom_alignment_* 等 production 資料)。需要在 client 上寫東西時,請建立專屬 scratch 目錄:
bash
sudo mkdir -p /mnt/nfs_share/master1_scratch
sudo chown beit:beit /mnt/nfs_share/master1_scratchNFSv4 clientaddr
nfsstat -m 會看到 clientaddr=10.248.36.248(NFSv4 callback 用的本機 IP,kernel 自動選)。多 NIC 且路由複雜時,可能選錯導致 delegation callback 失敗,可手動指定:
fstab
nfs _netdev,nofail,noatime,clientaddr=10.248.36.248,...相關概念
- DRBD + Pacemaker NFS HA Cluster 完整復原 Runbook — NFS server 端的 HA cluster 故障排查與復原,client mount 問題若根因在 server 端,轉此文件
- Kubernetes 維運技巧速查 — NFS Provisioner 在 K8s 中的使用,PV 透過本文件的 NFS server 提供