findmnt —— 现代化的"看挂载"命令
一句话定义
findmnt 是 mount 命令的现代继任者——树形输出、可过滤、可指定列、JSON 输出。K8s 节点排错挂载问题首选。
典型场景
- 看节点上所有挂载(树形结构):
findmnt - 看某 PV 在节点上的挂载:
findmnt /var/lib/kubelet/.../<pv-id> - 看挂载选项:
findmnt -o TARGET,SOURCE,OPTIONS - 验证 fstab:
findmnt --verify - 找哪个挂载源 = 某设备:
findmnt /dev/sdb1
1. 默认输出(树形)
$ findmnt
TARGET SOURCE FSTYPE OPTIONS
/ /dev/sda3 ext4 rw,relatime
├─/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime
│ ├─/sys/kernel/security securityfs securityfs rw,nosuid,nodev,noexec,relatime
│ ├─/sys/fs/cgroup cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate
│ ├─/sys/fs/pstore pstore pstore rw,nosuid,nodev,noexec,relatime
│ └─/sys/fs/bpf bpf bpf rw,nosuid,nodev,noexec,relatime
├─/proc proc proc rw,nosuid,nodev,noexec,relatime
├─/dev udev devtmpfs rw,nosuid,relatime,size=...
│ ├─/dev/pts devpts devpts rw,nosuid,noexec,relatime
│ ├─/dev/shm tmpfs tmpfs rw,nosuid,nodev
│ └─/dev/mqueue mqueue mqueue rw,nosuid,nodev,noexec
├─/run tmpfs tmpfs rw,nosuid,nodev,size=...
├─/boot /dev/sda2 ext4 rw,relatime
├─/var/lib/docker overlay overlay rw,...
└─/data /dev/sdb1 ext4 rw,noatime
字段:
| 列 | 含义 |
|---|---|
| TARGET | 挂载点 |
| SOURCE | 源(设备 / NFS / tmpfs / overlay) |
| FSTYPE | 文件系统类型 |
| OPTIONS | mount options |
树形显示bind mount / mount over mount 的层次。
2. 比 mount 命令好在哪
$ mount
# 一行一个挂载、无层次、长行难读
/dev/sda3 on / type ext4 (rw,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
...
$ findmnt
# 树形、对齐、易读
K8s 节点上 mount 通常 100+ 行——findmnt 整洁很多。
3. 核心 flag
findmnt -t ext4 # 只看某 FSTYPE
findmnt -t nfs4 # 只看 NFS
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS # 自定义列
findmnt /data # 看某挂载点
findmnt /dev/sdb1 # 看某设备
findmnt --source /dev/sdb1 # 同上、显式按 SOURCE 找
findmnt -l # 列表(非树形)
findmnt -R /var # 递归显示 /var 下的所有 mount
findmnt -J # JSON 输出
findmnt -P # parsable shell 友好(key=value)
findmnt -D # df 风格(含使用量)
findmnt --target / # 只显示 target = /
findmnt --types nfs,nfs4 # 多类型
findmnt --notruncate # 不截断长列
4. 可用列(自定义输出)
$ findmnt --help | grep -A 50 "Available columns"
TARGET filesystem 挂载点
SOURCE 设备/源
FSTYPE 文件系统类型
OPTIONS mount 选项
VFS-OPTIONS VFS 选项
FS-OPTIONS FS 特定选项
LABEL 文件系统 label
UUID UUID
PARTUUID 分区 UUID
PARTLABEL 分区 label
MAJ:MIN 主次设备号
ACTION propagation
PROPAGATION shared/private/slave/unbindable
ID mount ID
PARENT parent mount ID
SIZE 文件系统大小
AVAIL 可用
USED 已用
USE% 用量百分比
FSROOT 源的子路径(bind mount 显示)
TID task ID
NETNS netns
SOURCES 所有源(btrfs subvol 等)
常用组合
# 看 mount 全部信息
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS,FSROOT
# 看用量(df 风格)
findmnt -D
# 或自定义
findmnt -o TARGET,FSTYPE,SIZE,USED,AVAIL,USE%
# 看 propagation 模式(mount propagation 排查)
findmnt -o TARGET,SOURCE,PROPAGATION
5. FSROOT 列 —— 看 bind mount 的真实"源子路径"
$ findmnt -o TARGET,SOURCE,FSTYPE,FSROOT /etc/hosts
TARGET SOURCE FSTYPE FSROOT
/etc/hosts /dev/sda3 ext4 /var/lib/kubelet/pods/<uid>/etc-hosts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
这是 K8s bind mount 进来的真实路径!
K8s pod 里的 /etc/hosts 看似"在 ext4 上、源是 sda3",实际是 bind mount from /var/lib/kubelet/pods/<uid>/etc-hosts。
FSROOT 是揭穿"看似 mount 实则 bind"的关键。
6. 看 mount propagation
$ findmnt -o TARGET,PROPAGATION
TARGET PROPAGATION
/ shared
├─/run shared
├─/var/lib/kubelet shared
│ └─/var/lib/kubelet/pods/.. shared
└─/sys/fs/cgroup shared
值:
| Propagation | 含义 |
|---|---|
shared | 双向(rshared) |
private | 隔离(rprivate) |
slave | 节点 → 容器单向(rslave) |
unbindable | 罕用 |
排查 K8s CSI / mount propagation 必看(详见 container-volumes)。
7. --verify —— 验证 fstab
$ findmnt --verify --verbose
/ : target exists
: source UUID=abc-... successfully mapped to /dev/sda3
: FS type "ext4" is supported
: mount options compatible
/boot : target exists
: ...
/data : target does not exist
^^^^^^^^^^^^^^^^^^^^^^^^^
fstab 配错的早期警告
Success, no errors or warnings detected
或者:
... 1 error ...
写完 fstab、reboot 之前永远 findmnt --verify——比直接 reboot 后掉到 emergency mode 强。
详见 fstab.md。
8. 实战场景
场景 1:看 K8s pod 实际挂载
$ PID=$(crictl inspect $(crictl ps -q --name my-pod) | jq '.info.pid')
# 看 pod 视角
$ nsenter -t $PID -m findmnt
TARGET SOURCE FSTYPE OPTIONS
/ overlay overlay rw,relatime
├─/dev tmpfs[/dev] tmpfs rw,...
├─/proc proc proc rw,...
├─/etc/hosts /dev/sda3[/var/lib/kubelet/pods/.../etc-hosts]
├─/etc/resolv.conf /dev/sda3[/var/lib/kubelet/pods/.../resolv.conf]
├─/etc/hostname /dev/sda3[/var/lib/kubelet/pods/.../hostname]
├─/var/run/secrets/kubernetes.io/serviceaccount tmpfs tmpfs ro,relatime
└─/data /dev/sdb1[/var/lib/kubelet/pods/.../volumes/.../data] ext4
[] 里就是 FSROOT——bind mount 的真实子路径。
场景 2:排查"PV 没挂上"
$ kubectl exec my-pod -- df /data
df: /data: No such file or directory
# 节点上看
$ ssh m4
$ findmnt -o TARGET,SOURCE,FSTYPE | grep <pod-uid>
# 空?挂载没成功
# 看 kubelet 期望的位置
$ ls /var/lib/kubelet/pods/<pod-uid>/volumes/
kubernetes.io~csi/ ← 目录在
但 findmnt 看不到 = mount 失败
# CSI 状态
$ kubectl logs -n kube-system <csi-node-pod> | grep -i mount
详见 03-pv-pvc。
场景 3:找占某 mount 点的所有 pod
# 节点上找用 /mnt/shared 的所有 bind
$ findmnt -lo TARGET,SOURCE -O bind | grep "/mnt/shared"
/var/lib/kubelet/pods/abc.../volumes/.../mnt/shared /dev/sdb1[/mnt/shared]
/var/lib/kubelet/pods/def.../volumes/.../mnt/shared /dev/sdb1[/mnt/shared]
→ 2 个 pod 共享同一 mount。
场景 4:监控 mount 数量
K8s 节点 mount 数量过多可能拖累系统:
$ findmnt -l | wc -l
1500 ← 太多
1000+ 通常是 CSI / kubelet bind mount 没清干净。可能 pod 卡 Terminating。
场景 5:找含某 fstype 的所有 mount
$ findmnt -t nfs,nfs4
TARGET SOURCE FSTYPE OPTIONS
/mnt/shared nfs.example.com:/exports/data nfs4 rw,relatime,vers=4.2
$ findmnt -t overlay
TARGET SOURCE FSTYPE
/var/lib/containerd/.../snapshots/.../merged overlay overlay
... (大量 K8s 容器 overlay)
9. 反面教材
反面 1:用 mount 命令排查 K8s mount
$ mount | wc -l
500 ← 几百行难看
$ mount | grep <pod-uid> ← 文本搜
findmnt 树形 + 过滤 + 自定义列 = 舒服十倍。
反面 2:忘了 findmnt 默认是树形、grep 不便
$ findmnt | grep /data
└─/data ... ← 含树形字符、grep 还行但不整齐
要 grep 用 -l 转线性:
findmnt -l | grep /data
或者直接用 findmnt /data —— findmnt 自带过滤。
反面 3:误以为 findmnt 显示进程级
findmnt 显示节点 root mount namespace 的 mount。要看 pod 视角必须配 nsenter:
nsenter -t $PID -m findmnt
详见 nsenter.md。
反面 4:JSON 输出过滤忘了 --task
findmnt -J
# 默认输出所有挂载
findmnt -J --task=1
# 等价 cat /proc/1/mountinfo 的 JSON 友好版
按 task / PID 看视角。