AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

lsblk / df / du —— 三个被混淆的"看磁盘"命令

一句话定义

这三个命令经常被一起提,但看的是完全不同的东西:

  • lsblk —— 看块设备(物理盘、分区、LVM、加密层),无关是否挂载
  • df —— 看已挂载的文件系统用了多少
  • du —— 看某个目录树实际占多少

理解清楚这三个的分工,是装机和排查"磁盘满了"问题的基本功。


三者对比

维度lsblkdfdu
看什么块设备拓扑(盘 → 分区 → 文件系统)文件系统级用量目录树级用量
单位字节 / 人类可读文件系统块目录/文件大小
不挂载也能看✅❌(只列已挂载)❌(要能进入目录)
找"哪个目录占空间"❌❌✅
找"磁盘没挂上"✅❌❌
找"文件系统满了"❌✅❌
速度瞬时瞬时慢(要遍历目录)

装机第一个该跑的是 lsblk,不是 df。

df 只显示已挂载的文件系统,可能有大盘没挂载、或者挂在莫名其妙的 /www 路径上等着 Day1 处理 —— df 看不见,lsblk 才看得见。


lsblk —— 块设备拓扑

默认输出

$ lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda       8:0    0   100G  0 disk
├─sda1    8:1    0   512M  0 part /boot/efi
├─sda2    8:2    0     1G  0 part /boot
└─sda3    8:3    0  98.5G  0 part /
sdb       8:16   0   500G  0 disk                  ← 注意这块盘没挂载
nvme0n1 259:0    0   1.8T  0 disk
└─nvme0n1p1 ... part

读法:

  • 树形结构:sda 是磁盘,sda1/2/3 是它的分区
  • MOUNTPOINTS 空 → 没挂载(装机时这是最该关心的信号)
  • SIZE 列:人类可读
  • RM:是否可移动设备
  • RO:只读

上面例子里 sdb 是 500G 的盘但没挂,要么你忘了挂、要么 IDC 给你算了但没初始化。

最常用的几个 flag

lsblk -f                         # 加上文件系统类型和 UUID
lsblk -nbo NAME,SIZE,TYPE,MOUNTPOINT   # 字节单位 + 自定义列 + 无表头(脚本用)
lsblk -d                         # 只显示磁盘,不显示分区
lsblk -p                         # 显示完整路径(/dev/sda 而不是 sda)
lsblk -J                         # JSON 输出(脚本里配 jq 用)

lsblk -f 看文件系统

$ lsblk -f
NAME    FSTYPE FSVER LABEL UUID                                 MOUNTPOINTS
sda
├─sda1  vfat   FAT32       7E3D-AB42                            /boot/efi
├─sda2  ext4   1.0         a1b2c3d4-...                         /boot
└─sda3  ext4   1.0         e5f6g7h8-...                         /
sdb     ext4   1.0         <empty>                              ← 已格式化但没挂

FSTYPE 空 → 没格式化,要 mkfs.ext4 /dev/sdX。 有 FSTYPE 但 MOUNTPOINTS 空 → 已格式化但没挂,要写 /etc/fstab 或临时 mount。

装机典型用法

# 字节级、无表头、自定义列 —— 脚本最爱
lsblk -nbo NAME,SIZE,TYPE,MOUNTPOINT

# 看出哪块盘最大、是否挂载
lsblk -d -o NAME,SIZE,MODEL,SERIAL
# 用厂商/序列号区分多盘

df —— 文件系统用量

默认输出

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        98G   45G   49G  48% /
/dev/sda2       974M  120M  786M  14% /boot
tmpfs           3.9G  8.0K  3.9G   1% /run
overlay          98G   45G   49G  48% /var/lib/docker/...
  • -h 人类可读(K/M/G/T)
  • -T 显示文件系统类型(很有用,能看出哪个是 tmpfs / overlay)
  • -i 看 inode 用量(重要,下文专门讲)

df -h 看不全的东西

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  8.0K  3.9G   1% /run
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs           791M  1.2M  790M   1% /run/user/1000

很多 tmpfs / overlay 看着像独立"盘"实际是内存或映射,不消耗磁盘。看真实磁盘用量加 -T:

df -hT | grep -E 'ext4|xfs|btrfs|zfs'

df -i 看 inode 用量(坑王)

$ df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/sda3      6291456 6291300     156  100% /     ← inode 满了!

文件系统不仅有"字节空间",还有"inode 空间"。每个文件占一个 inode。如果有几百万个小文件(比如 K8s 的 hostPath logs 没清理),字节空间没满但 inode 满了,新文件创建失败。

df -h 看到 Use% 才 50%,但实际写不进去 —— 一定要看 df -i。

排查 docker / kubelet 撑满的 overlay

df -h
# overlay          98G   95G    3G  97% /var/lib/docker/overlay2/...

K8s 节点上 overlay 暴涨,常见原因:

  • 容器日志没轮转
  • 镜像太多没清(crictl rmi --prune)
  • emptyDir 写爆

排查接下来用 du。


du —— 目录树用量

默认输出(小心爆量)

du /var/log
# 每个子目录一行,能滚屏一万行

du 不加参数就递归显示每一个子目录。基本没人这么用。

常用 flag

du -sh /var/log                  # -s summary 总和,-h 人类可读
# 1.2G  /var/log

du -sh /var/*                    # 看 /var 下每个一级子目录占多少
du -sh /var/* 2>/dev/null | sort -h    # 按大小排序

du -h --max-depth=1 /var         # 同上,新写法

-h --max-depth=N 是排查"哪个目录占空间"的标配。

找最大的 N 个文件 / 目录

# 最大的 10 个文件
du -ah /var | sort -rh | head

# 最大的 10 个一级子目录
du -sh /var/* 2>/dev/null | sort -rh | head

du vs ls -l 大小不一致?

ls -l file.log
# -rw-r--r-- 1 root root 10737418240 ... file.log    ← 10 GB

du -sh file.log
# 4.0K  file.log                                       ← 才 4K?

稀疏文件(sparse file)—— 文件逻辑大小 10G,但实际只占 4K(中间全是空洞,文件系统不分配实际块)。ls -l 看逻辑大小,du 看物理占用。

K8s 里某些 PV 文件、数据库初始化文件经常是稀疏的。


实战:节点根分区满了,怎么排查

经典故障链:df -h(发现哪个 mount 满)→ du(找哪个子目录占)→ 处理。

# 第 1 步:哪个分区满了
df -h
# /dev/sda3        98G   97G  1.0G  99% /

# 第 2 步:根下哪个目录最大
du -sh /* 2>/dev/null | sort -rh | head
# 50G  /var
# 30G  /home
# 10G  /opt
# ...

# 第 3 步:钻进 /var 继续
du -sh /var/* 2>/dev/null | sort -rh | head
# 40G  /var/lib/docker
# 8G   /var/log
# ...

# 第 4 步:继续钻
du -sh /var/lib/docker/* 2>/dev/null | sort -rh | head
# 35G  /var/lib/docker/overlay2
# ...

# 第 5 步:清掉
docker system prune -af          # 或 crictl rmi --prune
journalctl --vacuum-size=500M    # journald 日志限大小

inode 满了怎么排查

df -i
# /dev/sda3 ... 100% /

# 找谁文件最多
for d in /*/; do
  echo "$(find "$d" -xdev | wc -l) $d"
done | sort -rn | head

-xdev 让 find 不跨文件系统(不进入 tmpfs / 别的挂载点)。

常见元凶:

  • K8s 的 /var/lib/kubelet/pods/*/volumes/... 几万个小 socket / configmap
  • /tmp 没清理
  • 日志切片太碎(logrotate 没启用、或 retention 太长)

常见踩坑

坑 1:装机只看 df,错过未挂载的盘

df 看不到没挂载的盘。Day0 必须先 lsblk 看完整拓扑,确认所有盘都被识别、再决定怎么挂。

坑 2:删完文件 df 没变

rm /var/log/huge.log             # 删了
df -h                            # 用量没降!

某进程还持有这个文件的句柄(典型:journald、应用日志没轮转)。Linux 文件系统的语义:句柄没关、文件实际不会释放。

排查:

lsof | grep deleted
# 或
lsof | grep huge.log

解决:重启那个进程(或 systemctl restart 该服务),文件句柄关了 → 空间释放。

坑 3:df -h Used + Avail < Size

# /dev/sda3   98G   80G   13G  87% /
# 80 + 13 = 93G,不是 98G?

不是 bug。ext4 默认保留 5% 给 root 用户用(tune2fs -m 0 可以改),普通用户用不到这部分,所以"Avail"不等于"Size - Used"。

坑 4:du 跟着 symlink 跑

du -sh /var
# 慢得要死、数字也不对

如果 /var/something 是个 symlink 指向别的 mount,du 默认不跨 mount 但会跟 symlink。加 -x(同 -xdev)只在当前文件系统内:

du -sh -x /var

坑 5:lsblk 看不到刚插的盘

$ lsblk
# 还是旧的拓扑

云厂商热添加盘之后,内核可能没刷。强制扫描:

echo "- - -" > /sys/class/scsi_host/host0/scan
# 或
partprobe
lsblk

关联命令

  • mount / umount —— 挂载文件系统
  • mkfs.ext4 / mkfs.xfs —— 格式化
  • fdisk / parted —— 分区表管理
  • lsof | grep deleted —— 找被进程持有的已删文件
  • systemctl —— 重启占着文件的服务
  • find —— 配合 -size 找大文件
在 GitHub 上编辑此页