AI Infra 训练营
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • 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
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • 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
  • 命令手册总览
  • SSH 与远程执行

    • ssh —— 远程登录与远程执行
    • ssh-config —— ~/.ssh/config 客户端配置文件
    • ssh-keygen —— 密钥对生成与 known_hosts 维护
    • sshd —— SSH 服务端守护进程与硬化
    • sshpass —— 密码登录自动化(仅限"首次推 key"场景)
    • scp / rsync —— 远程文件拷贝
    • nsenter —— 进入 Linux namespace 的"传送门"
  • 系统状态与诊断

    • systemd-detect-virt —— 探测当前运行环境的虚拟化类型
    • systemctl —— systemd 服务管理的总入口
    • journalctl —— systemd 日志查询
    • hostnamectl / timedatectl —— 改主机名与时区
    • ss —— socket statistics(替代 netstat)
    • lsblk / df / du —— 三个被混淆的"看磁盘"命令
  • 进程与资源

    • ps —— 看进程
    • top / htop —— 实时进程资源监控
    • lsof —— 列出打开的文件(list open files)
    • strace —— 系统调用追踪
    • dmesg —— 看内核环形缓冲日志
    • iostat —— 磁盘 I/O 性能分析
    • iotop —— 进程级 I/O 实时监控
  • 文本与文件批处理

    • grep —— 文本搜索
    • sed —— 流编辑器
    • awk —— 按字段处理文本
    • jq —— JSON 命令行处理器
    • find —— 按各种条件找文件
    • xargs —— 把 stdin 喂给下一个命令
    • tee —— 一边输出、一边写文件
  • 磁盘与存储

    • mount / umount —— 挂载文件系统
    • mkfs —— 格式化文件系统
    • /etc/fstab —— 持久化挂载配置
    • parted / fdisk —— 分区表管理
    • LVM —— pvcreate / vgcreate / lvcreate 三件套
    • findmnt —— 现代化的"看挂载"命令
    • nfsstat / showmount —— NFS 状态与性能
    • smartctl —— 盘健康检查与坏盘预警
  • 网络诊断

    • curl —— HTTP 客户端的瑞士军刀
    • ip —— 现代 Linux 网络配置工具(替代 ifconfig / route)
    • iptables —— Linux 内核包过滤 / NAT 规则
    • tcpdump —— 命令行抓包
    • dig —— DNS 查询工具
    • mtr —— traceroute + ping 合体
    • iperf3 —— 网络带宽测试
    • nc (netcat) —— 网络瑞士军刀
    • ethtool —— 物理网卡参数 / 速率 / offload
  • 内核 / 包管理 / 时间

    • modprobe / lsmod —— 内核模块加载
    • sysctl —— 内核运行时参数
    • apt / apt-get / dpkg —— Debian / Ubuntu 包管理
    • chrony / chronyc —— NTP 时间同步
  • K8s / 容器工具链

    • kubectl —— K8s 的瑞士军刀
    • kubeadm —— K8s 集群引导工具
    • helm —— K8s 应用包管理器
    • crictl —— 容器运行时命令行(CRI 层)
    • etcdctl —— 直连 K8s 元数据存储
    • docker —— 单机容器(构建和本地开发)
  • 监控 / GitOps / 备份

    • argocd —— GitOps CLI
    • velero —— K8s 集群备份恢复
    • prometheus / promtool —— 监控数据查询和工具
    • cilium / cilium-cli / hubble —— eBPF CNI 排错
    • grafana / grafana-cli —— 可视化平台运维
    • alertmanager / amtool —— 告警分组、抑制、路由
  • 开发 / 构建 / 终端

    • git —— 版本控制 + GitOps 的底座
    • make / Makefile —— 任务编排
    • openssl —— 证书 / 密钥 / TLS 调试工具箱
    • tmux —— 终端复用 / 长跑任务防掉线
    • vim —— 远程编辑必备最小集
    • cron / crontab —— 定时任务

lsof —— 列出打开的文件(list open files)

一句话定义

lsof 列出进程打开的文件——包括普通文件、目录、设备、网络 socket、unix socket、pipe、设备等。在 Linux 里"一切皆文件",所以 lsof 能回答各种"谁在用什么"的问题。

典型场景

  • "为啥端口被占了":lsof -i :8080
  • "rm 文件但磁盘没释放":lsof | grep deleted
  • "为啥这个 unmount 不掉":lsof <mount-point>
  • "containerd.sock 谁在连":lsof /run/containerd/containerd.sock
  • "进程打开了多少 fd":lsof -p <PID> + wc -l

装

apt install -y lsof              # Debian / Ubuntu
yum install -y lsof              # CentOS / RHEL

大多数系统自带。


输出格式

COMMAND   PID USER   FD   TYPE     DEVICE  SIZE/OFF   NODE NAME
sshd     1234 root  cwd    DIR        8,3      4096      2 /
sshd     1234 root  rtd    DIR        8,3      4096      2 /
sshd     1234 root  txt    REG        8,3    855648 123456 /usr/sbin/sshd
sshd     1234 root  mem    REG        8,3    166400 123457 /lib/x86_64-linux-gnu/libc.so.6
sshd     1234 root    0u   CHR        1,3       0t0      6 /dev/null
sshd     1234 root    3u  IPv4     123456      0t0    TCP *:22 (LISTEN)
sshd     1234 root    4u  IPv6     123457      0t0    TCP *:22 (LISTEN)
列含义
COMMAND进程名
PID进程 ID
USER拥有者
FD文件描述符(数字 + 模式 / 特殊标记)
TYPE文件类型
DEVICE主设备号 / 次设备号
SIZE/OFF大小或偏移量
NODEinode
NAME文件名 / socket 描述

FD 列的特殊值

值含义
cwdcurrent working directory
rtdroot directory(chroot 后)
txttext(可执行文件本身)
mem内存映射文件
0u / 1u / 2ustdin / stdout / stderr(u = read/write)
3r / 3w / 3u数字 + r (read) / w (write) / u (both)

TYPE 列

值含义
REG普通文件
DIR目录
CHR字符设备
BLK块设备
FIFO命名管道
IPv4 / IPv6网络 socket
unixunix domain socket

核心 5 个用法

1. lsof -i :<port> —— 谁占了某端口

lsof -i :8080
# COMMAND  PID  USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
# nginx   1234  root    6u  IPv4  123456    0t0    TCP *:8080 (LISTEN)

也可以指定协议:

lsof -i tcp:8080
lsof -i udp:53
lsof -i 4 -i tcp                       # 仅 IPv4 TCP
lsof -i @10.0.24.28                    # 跟某 IP 相关的连接
lsof -i @10.0.24.28:6443                # 跟某 IP:port 相关

2. lsof <path> —— 谁打开了某文件

lsof /var/log/syslog
# COMMAND  PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# rsyslogd 567 root 8w REG  8,3    1234567   ... /var/log/syslog

3. lsof <directory> —— 谁在用某目录

lsof +D /mnt/data
# +D 递归显示该目录下的所有
# 慢但全面

排查 umount: device is busy 必备。

4. lsof -p <PID> —— 某进程打开的所有文件

lsof -p 1234 | head
lsof -p 1234 | wc -l                   # 这进程打开了多少 fd

5. lsof -u <user> —— 某用户打开的

lsof -u root
lsof -u nginx -i                       # nginx 用户的网络连接

实战场景

场景 1:端口被占用

$ systemctl start nginx
Job for nginx.service failed because the control process exited with error.
# ... bind: Address already in use

$ lsof -i :80
# COMMAND  PID  USER FD TYPE DEVICE SIZE/OFF NODE NAME
# httpd   2345  root 4u IPv4 234567    0t0   TCP *:80 (LISTEN)

# 是 Apache 在占!
systemctl stop apache2
systemctl start nginx

ss -lntp 是更现代的等价物,但 lsof -i 在某些场景更直观(含进程名)。

场景 2:rm 文件后磁盘没释放

df -h /
# /dev/sda3   95% full

rm /var/log/huge.log
df -h /
# /dev/sda3   95% full         ← 还是满的!

lsof | grep deleted
# rsyslogd  567  root  8w  REG  8,3  10737418240  123456 /var/log/huge.log (deleted)

某进程持有这个文件的句柄 → Linux 不真释放空间。

修:

systemctl restart rsyslog        # 重启那个进程,句柄关 → 空间释放

# 或者优雅一点(不重启)让进程关那个 fd:不容易,多数情况只能 restart

K8s 节点上 journald / kubelet / containerd 是常见占用者。

场景 3:umount 卡住

$ umount /mnt/data
umount: /mnt/data: target is busy.

$ lsof +D /mnt/data | head
# COMMAND  PID  USER FD TYPE DEVICE SIZE/OFF NODE NAME
# bash    3456  root cwd DIR   8,16   4096    1   /mnt/data
# vim     4567  root  3u REG   8,16   1234    2   /mnt/data/notes.txt

找到占用者,kill 或者让它退出,再 umount。

或者懒卸载:

umount -l /mnt/data              # lazy 立刻断开 mount,但保留旧 fd 工作直到关闭

场景 4:进程打开太多 fd

lsof -p 1234 | wc -l
# 65000           ← 接近 ulimit 上限

# 看大概是什么
lsof -p 1234 | awk '{print $5}' | sort | uniq -c | sort -rn | head
# 60000 IPv4              ← 大部分是网络连接
#   200 REG
#   ...

fd 泄漏。看应用代码。

场景 5:找跟 unix socket 相关的进程

# 谁在连 containerd
lsof /run/containerd/containerd.sock
# COMMAND  PID    USER  FD TYPE  DEVICE SIZE/OFF NODE NAME
# kubelet  1234   root  5u unix 0x...  0t0      ... /run/containerd/containerd.sock

# 谁在连 docker
lsof /var/run/docker.sock

排查"kubelet 连不上 containerd" / "kubectl exec 卡"。

场景 6:看 K8s pod 内进程开的文件

# 找 pod 容器的 PID
PID=$(crictl inspect $(crictl ps -q --name my-pod) | jq '.info.pid')

# 看它开了什么
lsof -p $PID

# 看它的网络连接
lsof -p $PID -i

# 看是不是 fd 泄漏
lsof -p $PID | wc -l

注意:在节点 root 上跑 lsof 看 pod 进程的 fd 是看不到 pod 内 mount 视角的路径(namespace 隔离)—— 你看到的是宿主机的路径。

要 pod 视角:

nsenter -t $PID --mount --net lsof -p $PID

看网络连接

lsof -i                                # 所有网络连接
lsof -i tcp                            # 只 TCP
lsof -i -P -n                          # -P 不解析端口名,-n 不解析 IP
lsof -i :22                            # 22 端口
lsof -i tcp:80-443                     # 端口范围
lsof -i @gateway.local                 # 跟某主机相关
lsof -i 4 -i :443                      # IPv4 + 443

-P -n 标配:不加的话 lsof 会反向 DNS + 解析端口名,慢。

lsof -i -P -n | grep ESTABLISHED
# 所有已建立的网络连接

lsof vs ss 在网络场景的对比

维度sslsof -i
速度快(netlink)慢(遍历所有进程)
信息网络专用,无进程文件综合
看哪个进程-p自带
TCP 状态过滤state establishedgrep
推荐日常优先用 sslsof 在排错复杂场景
ss -lntp                               # 看监听 + 进程,简洁快
lsof -i :8080                          # 看 8080 端口被谁占(同等效果)

看进程的工作目录 / 已执行二进制

lsof -p 1234 -a -d cwd                 # cwd
# COMMAND   PID  USER  FD TYPE DEVICE SIZE/OFF NODE NAME
# python   1234  root  cwd DIR  8,3   4096    1234 /opt/myapp

lsof -p 1234 -a -d txt                 # 可执行文件(text 段)
# python   1234  root  txt REG  8,3   3000000 5678 /usr/bin/python3.10

-a 表示多个过滤条件 AND(默认是 OR)。 -d cwd 限定 fd 类型。

或者更直接:

readlink /proc/1234/cwd
readlink /proc/1234/exe
ls -l /proc/1234/fd/

训练营常用速查

# 谁占了 ApiServer 端口
lsof -i :6443

# 谁连 etcd
lsof -i :2379

# pod 内进程开的文件
lsof -p $(crictl inspect $(crictl ps -q --name my-pod) | jq '.info.pid')

# 找 deleted 文件释放磁盘
lsof | grep deleted | sort -k7 -rn | head

# 看 kubelet 与 containerd 的 unix socket
lsof /var/run/containerd/containerd.sock
lsof /var/run/cri.sock

# 排查节点出网慢:哪些进程在大量网络连接
lsof -i -P -n | awk '{print $1}' | sort | uniq -c | sort -rn | head

常见踩坑

坑 1:lsof 跑得超慢

lsof                                   # 几秒到几十秒

lsof 默认遍历所有进程的所有 fd——大节点几万个 fd。

加 flag 缩小范围:

lsof -p <PID>                          # 限定 PID
lsof -i :8080                          # 限定 socket
lsof -nP                               # 跳过 DNS / 服务名解析
lsof -c <command>                      # 按进程名

特别 -n -P 大幅提速。

坑 2:root 才能看全

$ lsof -i :22
# 没输出 / 只显示自己的进程

sudo lsof -i :22。看别人进程必须 root。

坑 3:lsof +D 慢得吓人

lsof +D /                              # 跑半小时

+D 递归一整个文件系统。只在小目录用:

lsof /mnt/data                         # 仅匹配这一层
lsof +D /mnt/data                      # 递归(慢)

坑 4:在容器里 lsof 看不到完整路径

$ kubectl exec my-pod -- lsof | head
# 路径是 pod 内的视角(/app/...)

容器有自己的 mount namespace,路径意义和宿主机不同。这是预期行为。

坑 5:alpine 容器没装 lsof

$ kubectl exec my-pod -- lsof
sh: lsof: not found

alpine 默认没 lsof。装:apk add lsof。

或者用 /proc:

ls -l /proc/<PID>/fd/                  # 等价 lsof -p

坑 6:FD 列出现奇怪的字母

FD
NOFD             ← 无法读取 fd 信息(权限不够)
cwd
DEL              ← 已删除的内存映射
ERR              ← 读 fd 失败

NOFD 通常是没权限;DEL 是 mmap 的文件已被删除,但仍在内存里映射。

坑 7:lsof 没显示 "deleted" 但 du / df 差很多

du -sh /var               # 5 GB
df /var                   # used 15 GB

差 10 GB。lsof 应该能找到 deleted 文件,但有些类型的"被持有的空间"lsof 看不到:

  • tmpfs 中的内存(restart 才释放)
  • 容器 overlay 层
  • 旧 kernel 中的 mmap

通用排查:

lsof | grep deleted
ls -la /proc/*/fd/* 2>/dev/null | grep deleted

坑 8:-i 和 -c 混用语义

lsof -i :80 -c nginx                   # 默认 OR
lsof -a -i :80 -c nginx                # AND

要"既符合 -i 又符合 -c" 必须加 -a。多数 lsof 选项默认 OR,反直觉。


关联命令

  • ss —— 网络场景比 lsof 快
  • ps —— 找 PID
  • strace —— 看进程实时 syscall
  • fuser —— 简化版 lsof(只显示 PID):fuser -v /mnt/data
  • du -sh + lsof | grep deleted —— 排查"磁盘满"组合拳
  • crictl —— 找 pod 容器的 PID
  • /proc/<PID>/fd/ —— lsof 看不到时用这个
在 GitHub 上编辑此页
Prev
top / htop —— 实时进程资源监控
Next
strace —— 系统调用追踪