“这个端口被谁占了?” 每个开发者都问过这个问题,然后对着 lsof 的输出一脸懵。

问题背景

本地开发时,端口冲突是家常便饭:

1
2
3
4
5
6
7
# 传统排查方式
lsof -iTCP:3000 -sTCP:LISTEN
# 输出一堆看不懂的东西...

# 或者
netstat -tlnp | grep 3000
# 需要 sudo,输出也不直观

痛点很明显:

场景 传统做法 问题
端口被占用 lsof + grep 输出冗长,看不出是 Docker 还是本地进程
查看 Docker 端口 docker ps + 手动映射 容器端口和宿主机端口对不上
批量管理服务 逐个 kill 低效,容易误杀
等待服务启动 轮询 curl 写脚本麻烦,逻辑不统一

Sonar 就是为了解决这些问题而生的。


Sonar 是什么

Sonar 是一个用 Go 写的 CLI 工具,专门用来查看和管理 localhost 上监听的端口。

关键数字

  • GitHub Stars: 1,000+
  • 语言: Go (88.9%) + Swift (7.5%)
  • 许可证: MIT
  • 支持平台: macOS、Linux、Windows
  • 安装方式: Homebrew / 脚本 / Go

核心定位

1
2
3
4
5
Sonar 让你一眼看清本地端口在跑什么。
- 列出所有监听端口
- 显示 Docker 容器名、镜像、映射端口
- 支持 kill 进程、查看日志、shell 进入容器
- 等待端口就绪(脚本友好)

核心特性

1. 端口一目了然

1
2
3
4
5
6
7
8
9
$ sonar list
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

5 ports (4 docker, 1 user)

不用再猜了:哪个端口、什么进程、是不是 Docker、映射到哪——全都有。

2. Docker 深度集成

Sonar 不是简单地调用 docker ps,它会:

  • 显示容器名、镜像名、Compose 项目
  • 区分 Docker 端口和用户进程
  • 支持 docker stop 优雅停止容器
  • 查看容器日志(docker logs -f

3. 资源监控

1
sonar list --stats

输出 CPU、内存、运行时间、状态等信息,类似 docker stats 但更全面。

4. 脚本友好的等待机制

1
2
3
4
5
6
7
8
9
# 等待端口就绪
sonar wait 5432 3000 --timeout 60s

# 等待 HTTP 200(不只是 TCP 连接)
sonar wait 3000 --http=/health

# 配合 docker compose
docker compose up -d
sonar wait 5432 3000 --timeout 60s && npm run migrate && npm run test

这在 CI/CD 或本地脚本里特别有用。


快速开始

安装

1
2
3
4
5
6
7
8
9
10
11
# macOS / Linux(推荐)
brew install raskrebs/sonar/sonar

# 或者用安装脚本
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | bash

# Windows (PowerShell)
irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex

# Go 用户
go install github.com/raskrebs/sonar@latest

Shell 补全

1
2
3
4
5
6
7
8
# zsh
sonar completion zsh > "${fpath[1]}/_sonar"

# bash
sonar completion bash > /etc/bash_completion.d/sonar

# fish
sonar completion fish | source

常用命令

查看端口

1
2
3
4
5
6
sonar list                     # 显示所有端口
sonar list --stats # 包含 CPU、内存、运行时间
sonar list --filter docker # 只显示 Docker 端口
sonar list --sort name # 按进程名排序
sonar list --json # JSON 输出(方便脚本处理)
sonar list -a # 包含桌面应用(默认隐藏 Figma、Spotify 等)

查看端口详情

1
sonar info 3000

显示完整信息:命令行、用户、绑定地址、资源使用、Docker 详情等。

杀进程

1
2
3
4
sonar kill 3000                # SIGTERM
sonar kill 3000 -f # SIGKILL
sonar kill-all --filter docker # 停止所有 Docker 容器
sonar kill-all --project my-app # 停止某个 Compose 项目

Docker 容器会用 docker stop 优雅停止,不是直接杀进程。

查看日志

1
sonar logs 3000
  • Docker 容器:调用 docker logs -f
  • 本地进程:通过 lsof 找到日志文件并 tail
  • macOS 回退:log stream
  • Linux 回退:/proc/<pid>/fd

进入容器

1
2
sonar attach 3000              # shell 进入 Docker 容器
sonar attach 3000 --shell bash # 指定 shell

实时监控

1
2
3
4
sonar watch                    # 每 2 秒刷新,显示变化
sonar watch --stats # 实时资源统计
sonar watch -i 500ms # 更快的刷新频率
sonar watch --notify # 端口变化时桌面通知

端口映射

1
sonar map 6873 3002

把 6873 端口的流量代理到 3002,方便调试。

找空闲端口

1
2
3
4
sonar next                     # 从 3000 开始找第一个空闲端口
sonar next 8000 # 从 8000 开始找
sonar next 3000-3100 # 在范围内找
sonar next -n 3 # 找 3 个连续空闲端口

依赖关系图

1
sonar graph

显示哪些服务在互相通信(比如 backend 连接 postgres)。


实用场景

场景 1: 快速定位端口冲突

1
2
3
# 端口 3000 被占了?
sonar info 3000
# 一看就知道是哪个进程,直接 kill

场景 2: Docker Compose 项目管理

1
2
3
4
5
6
7
8
# 查看项目所有端口
sonar list --filter docker

# 停止整个项目
sonar kill-all --project my-app

# 查看项目日志
sonar logs 3000 # 任意一个端口即可

场景 3: CI/CD 等待服务就绪

1
2
3
4
5
6
7
8
9
#!/bin/bash
docker compose up -d

# 等待数据库和 API 就绪
sonar wait 5432 3000 --timeout 60s --http=/health

# 服务就绪后执行迁移和测试
npm run migrate
npm run test

场景 4: 开发环境快速切换

1
2
3
4
5
6
7
8
# 保存当前端口配置
sonar profile create my-app

# 下次开发时检查
sonar up my-app

# 收工时一键停止
sonar down my-app

配置文件

Sonar 支持配置文件,位置在 ~/.config/sonar/config.yaml

1
2
3
4
5
6
7
8
# 生成配置模板
sonar config init

# 查看配置路径
sonar config path

# 编辑配置
sonar config edit

示例配置:

1
2
3
4
5
6
7
8
9
list:
columns: [port, process, container, image, containerport, url]
sort: port
filter: ""
all: false
color: true
services:
9000: php-fpm
5050: my-dashboard

macOS 菜单栏应用

Sonar 还有一个 macOS 菜单栏应用,实时显示端口状态:

1
sonar tray

通过 Homebrew 安装时会自动包含 sonar-tray


对比矩阵

工具 Docker 支持 资源监控 脚本集成 易用性
sonar ⭐⭐⭐⭐⭐
lsof ⚠️ ⭐⭐
netstat ⚠️ ⭐⭐
ss ⚠️ ⭐⭐⭐
docker ps ⚠️ ⭐⭐⭐

总结

Sonar 解决的核心问题:让本地端口管理变得直观

维度 价值
可视化 一眼看清所有端口,不用拼凑命令
Docker 集成 容器名、镜像、端口映射一目了然
脚本友好 wait 命令替代手写轮询逻辑
操作便捷 kill、logs、attach 一个命令搞定

推荐使用

1
2
3
4
本地开发 → sonar list(快速查看端口)
Docker 项目 → sonar list --filter docker(容器管理)
CI/CD → sonar wait(等待服务就绪)
日常监控 → sonar watch(实时观察)

延伸阅读


下次端口被占了,别再对着 lsof 发呆了。装个 sonar,一眼看清。