raskrebs 受够了。每次端口被占用,他都要敲一串 lsof -iTCP -sTCP:LISTEN | grep ...,再花一分钟猜这是 Docker 容器还是某个孤儿 dev server。于是他写了 sonar——一个 579 星、11 次 fork 的 Go 工具,把本地端口管理变成了单命令操作。
痛点有多真实?
开发者的 localhost 是个战场。3000 被 Next.js 占了,5432 躺着 PostgreSQL,8080 可能是三年前跑的 Spring Boot -demo。最烦的是:你知道有东西在跑,但不知道是什么、在哪、怎么杀。
raskrebs 的解决思路很直接:端口即入口。输入 sonar list,你拿到一张表——端口、进程名、容器名、镜像、映射端口、可点击的 URL。5 行输出,5 个端口的状态一目了然:4 个 Docker,1 个用户进程。
输出长这样:
PORT PROCESS CONTAINER IMAGE CPORT URL 1780 proxy (traefik:3.0) my-app-proxy-1 traefik:3.0 80 http://localhost:1780 3000 next-server (v16.1.6) http://localhost:3000 5432 db (postgres:17) my-app-db-1 postgres:17 5432 http://localhost:5432 6873 frontend (frontend:latest) my-app-frontend-1 frontend:latest 5173 http://localhost:6873 9700 backend (backend:latest) my-app-backend-1 backend:latest 8000 http://localhost:9700
注意细节:3000 那行没有容器信息,说明是裸进程跑在本地。其他四行把 Docker 的映射关系扒干净了——宿主机 1780 映射到容器 80,6873 映射到 5173。这种透明感,正是 docker ps 给不了的。
功能拆解:不止于"看"
sonar 的设计哲学是"端口即操作对象"。知道端口之后,你能直接干这些事:
杀进程:sonar kill 3000。不用 ps aux | grep node 找 PID,再 kill -9。端口就是把手。
看日志:sonar logs 5432。自动识别是容器还是普通进程,容器走 docker logs,进程尝试 tail 或关联的日志文件。
进容器:sonar shell 9700。端口 9700 对应 backend 容器?直接 docker exec -it 进去,省掉复制容器名的步骤。
加 stats:sonar list --stats 带上 CPU、内存、运行时长。对于排查"哪个服务在吃资源"这种日常任务,够用了。
Shell 补全也做了。sonar completion zsh 装好后,tab 键能补全端口号——这个小细节说明作者自己天天用。
安装路径:两条线,都很短
curl 一键装:curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/install.sh | bash。脚本干的事:下载最新二进制到 ~/.local/bin,PATH 没有就加上。想换位置?SONAR_INSTALL_DIR=/usr/local/bin 前置即可。
Go 用户更短:go install github.com/raskrebs/sonar@latest。28 次 commit 的轻量项目,依赖干净。
项目用 Go 写不是偶然。跨平台编译、单二进制分发、启动速度——这些特性对 CLI 工具是刚需。对比 Python 写的同类工具,sonar 没有虚拟环境、依赖冲突的麻烦。
为什么是现在?
本地开发环境的复杂度在 2020 年后陡增。Docker Desktop 普及、微服务 demo 遍地、前端框架每个项目都带 dev server。端口冲突从"偶尔遇到"变成"每天几次"。
现有方案各有别扭:
lsof/netstat:信息太裸,容器名看不到,Docker 映射关系要心算。
docker ps:只看容器,裸进程漏掉;端口映射要横着读,不直观。
IDE 插件:绑定特定编辑器,跨项目不一致。
sonar 的切入点很准:不替代 Docker,不替代系统工具,只做一层聚合——以端口为索引,把散落的信息拉到一起。
这个设计选择也有代价。它假设你的服务都绑在 localhost 的明确端口上,对于动态端口、Unix socket、或者 Kubernetes port-forward 的场景,覆盖不到。但 raskrebs 的目标用户很清晰:每天在本地跑 3-5 个服务的全栈开发者。
社区反馈的信号
579 star、11 fork、28 commit——数字不算爆炸,但比例健康。fork 率低说明"拿来即用"够好,commit 数少说明功能聚焦没乱加。GitHub 上这类"解决具体痒点"的小工具,往往比大而无当的平台项目活得久。
install.sh 用 bash 而不是更"现代"的手段,也是务实选择。目标用户的机器都有 bash,curl 管道安装是开发者熟悉的路径。没有追求 npm 式的生态锁定,没有配置文件要管,单二进制扔到 PATH 就完事。
Shell 补全支持 zsh/bash/fish 三家,覆盖主流。fish 的 | source 用法写进文档,说明作者真的用过 fish。
同类工具 landscape
端口管理不是新赛道。比较接近的有:
portman:Node 写的,功能类似但重一些,需要 npm 全局装。
lazydocker:TUI 界面,专注 Docker,不处理裸进程。
系统自带的 lsof+grep:sonar 想替代的正是这个。
sonar 的差异化在于"端口优先"的交互设计。不是给你一张大表自己翻,而是让你直接对端口号操作。这个抽象层很薄,但省掉的上下文切换很实在。
代码层面,Go 的标准库 net 包能扫监听端口,os/exec 调 lsof 或 docker 命令补信息。没有魔法,都是系统调用的封装。这种"薄封装"策略降低了维护负担,也让行为可预期。
潜在扩展与边界
看 README 的写法,raskrebs 对功能膨胀有警惕。sonar list --f 后面截断了,可能是 --filter 之类,但文档没展开。28 个 commit 的体量,核心功能应该已经定型。
能想到的自然延伸:配置文件支持(自定义端口别名)、历史记录(这个端口上周跑过什么)、远程主机支持(SSH 到服务器上执行)。但这些都会增加复杂度,违背"tiny CLI"的定位。
更可能的演进是插件化或脚本钩子。比如 sonar kill 3000 前执行自定义清理,或 sonar list 输出 JSON 供其他工具消费。Go 的接口设计让这类扩展不难做。
竞品防御上,Docker Desktop 如果内置类似功能,会挤压 sonar 的空间。但 Docker 的 UI 向来笨重,开发者对轻量 CLI 的偏好不会消失。更现实的威胁是同类工具的功能追赶——比如 lazydocker 加一个"端口视图"模式。
商业模式的空白
sonar 是 MIT 许可证的开源项目,没有付费层。raskrebs 的动机写得很清楚:"I got tired of..."——典型的开发者自挠其痒。
但这类工具的商业化路径其实清晰:
团队版:多机器端口同步、共享环境配置、冲突预警。
云桥接:本地端口映射到预览 URL,类似 ngrok 集成。
企业合规:审计日志、权限管控、敏感端口告警。
这些都不是 sonar 现在做的,也大概率不会走这个方向。但项目如果继续增长,GitHub Sponsors 或周边服务(如托管的 team 版本)是自然选项。
更值得关注的是"端口管理"作为基础设施的品类价值。随着本地开发环境云化(GitHub Codespaces、Gitpod),端口冲突问题会迁移到云端,但"快速定位服务"的需求不变。sonar 的交互范式——端口即把手——可以跨环境复用。
技术债与维护压力
Go 1.18+ 的依赖,单模块,没有 vendor 目录。install.sh 从 GitHub raw 拉取,没有签名验证——这是标准做法,但也是供应链攻击的潜在入口。如果项目 star 破万,这部分需要加固。
跨平台方面,Windows 的端口扫描和进程信息获取与 Unix 差异大。README 没提 Windows 支持,可能当前只覆盖 macOS/Linux。这对目标用户(主流是 macOS 开发者)暂时够用了。
测试覆盖、CI/CD 流程在 28 commit 的体量下大概率是轻量的。GitHub Actions 跑个 Go 测试、交叉编译 release 二进制,就是标准配置。
为什么是 CLI 而不是 TUI
lazydocker 用 TUI(文本用户界面),sonar 坚持纯 CLI。这个选择值得玩味。
TUI 的优势:信息密度高、键盘导航快、适合长时间盯屏。
CLI 的优势:可脚本化、输出可管道、学习成本低、启动瞬间。
sonar 的场景是"快速看一眼、操作一下",不是"持续监控"。CLI 的 list | grep、kill 3000 流程更贴合这个节奏。而且 TUI 依赖终端尺寸、颜色支持,跨环境一致性更难保证。
raskrebs 的选择说明他对使用场景有清晰判断:不是替代 Docker Desktop 的仪表盘,而是替代 shell 里的一串管道命令。
命名与品牌
sonar——声纳,探测水下物体的技术。隐喻很准:localhost 的水面下有什么,发一束信号扫一圈就知道。ASCII logo 也做了,五行的 SONAR 字母,放在 README 顶部。这种仪式感是开发者工具的标配,说明作者懂 GitHub 社区的审美。
对比随意命名的同类项目,sonar 有记忆点、有搜索友好度("sonar port" 的 SEO 竞争度低)、有延展空间(sonar probe、sonar sweep 等子命令不违和)。
一个未被满足的需求信号
看 HN 帖子的标题格式 "Show HN: ..."——这是 Hacker News 上开发者发布 side project 的标准前缀。579 star 说明它 resonated,但还没到病毒传播的程度。
更深层的需求可能是"本地开发环境的可观测性"。我们给生产环境堆满了监控,但 localhost 还是黑箱。sonar 是第一步:把端口层面的状态可视化。下一步可能是依赖图(服务 A 调服务 B)、配置漂移检测(这个容器的 env 和 docker-compose.yml 一致吗)、或者性能基准(这个端口的响应时间比上周慢了多少)。
但这些都会让 sonar 变重。raskrebs 现在的克制是对的:先解决 80% 场景,保持工具的单一天职。
冷幽默
sonar 的 README 最后一行是 sonar list --f,然后没了。像是作者写到一半被叫去开会,或者突然意识到"反正用户会 --help,懒得写了"。579 个人 star 了一个没写完文档的项目——这说明痛点是真的痛,痛到大家愿意自己猜。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.