我的NAS上跑着二十几个容器,SSH 进去排查问题时,经常遇到这样的场景:看到个陌生进程,不知道是哪个服务拉起来的,也不知道是哪个容器里的。以前的标准流程是 lsof 查端口、ps 看父子关系、systemctl 确认服务配置,三个命令来回切,有时候还得进 /proc 目录翻环境变量。
最近翻到 witr,这工具名字起得很直接——”Why Is This Running?”,一条命令就把启动链全展开。
装起来不费劲
跨平台支持做得挺全。macOS 直接 brew install witr,Linux 用安装脚本,Windows 有 winget 和 scoop。Go 写的单二进制,没依赖,装完就一个小文件。
项目 Apache 2.0 协议,GitHub 18k+ stars,更新节奏很快,v0.3.3 是两个月前的版本,但看提交记录一直在修 edge case。
一条命令看全启动链
最直接的用法是给个 PID:
witr 1234
输出不是干巴巴的一条进程信息,而是把因果链倒着展开:这个进程是谁启动的,上一层父进程是什么,最终追溯到 systemd 服务还是容器运行时。比我自己手动翻 /proc/{pid}/status 和 ppid 快得多。

查端口占用更省事。以前 lsof -i :3000 只能看到进程名,witr 直接给整条链:
witr --port 3000
能一眼看出这个端口是哪个 Docker 容器里的哪个进程绑定的,容器又是被哪个 compose 项目拉起来的。
容器和权限的边界
在 Linux 上 witr 能穿透 Docker 和 LXC 容器的边界,看到容器内部进程的启动链。但这个能力在 macOS 上受限——lsof 返回的 FD 格式跟 Linux 不一样,加上 SIP 的保护,有些系统进程只能看到一层壳,看不到完整链路。
另外一个提醒:查其他用户的进程或系统级服务需要 sudo,否则只能看到当前用户空间的东西。我第一次试时没加 sudo,结果一条链走到一半断了,还以为是 bug。
TUI 和 JSON 两种模式
除了终端直接输出,witr -i 会进入一个交互式 TUI 界面,上下翻进程列表,按回车展开详情。适合不想记命令的时候随手翻一翻。

如果要接脚本或监控告警,用 JSON 输出:
witr --json --port 8080 | jq '.causality_chain[-1].service'
退出码也有规范:0 成功、1 未找到、2 参数错误、3 运行时错误。做自动化巡检时可以直接判断。
踩过的一个小坑
witr 在 v0.3.3 之前有个 macOS 上的 bug:二进制被系统标记为删除状态时会出警告信息。v0.3.3 修掉了。另外 Homebrew 和 Go 直接安装的版本通常是最新的,但 Conda 和 AUR 里的包有时候会滞后,装之前最好确认一下版本。
Windows 版本我试了下,功能完整但输出信息比 Linux 精简一些,某些容器信息拿不到,毕竟 Windows 没有 systemd 和 cgroup 那套东西。
最后
这工具不是监控大盘,也不是进程管理器,就解决一个问题:搞清楚一个进程到底是从哪来的。对于手上一堆 Docker 容器、几个服务来回倒腾的人来说,能把排查时间从”三个命令来回切”压到”一条命令出结果”,已经够值了。