Go 远程调试教程 — Delve + VS Code
本文详细介绍了使用 Delve 和 VS Code 进行 Go 远程调试的完整流程,涵盖 Delve 安装(含交叉编译)、服务端二进制编译(避免 strip 调试符号)、通过 dlv attach 挂载进程、SSH 隧道转发、VS Code launch.json 配置及调试步骤。同时整理了端口监听失败、断点不生效等常见问题的排查方法,并提供了本地调试作为备选方案。
1. 安装 Delve
服务器有 Go 环境
go install github.com/go-delve/delve/cmd/dlv@latest
服务器无 Go 环境(交叉编译)
在开发机编译目标平台版本,然后传到服务器。
| 开发机平台 | 编译环境变量 | 产物路径 |
|---|---|---|
| Windows → Linux amd64 | GOOS=linux GOARCH=amd64 |
%USERPROFILE%\go\bin\linux_amd64\dlv |
| macOS → Linux amd64 | GOOS=linux GOARCH=amd64 |
~/go/bin/linux_amd64/dlv |
# Windows 示例
$env:GOOS = "linux"
$env:GOARCH = "amd64"
go install github.com/go-delve/delve/cmd/dlv@latest
scp /path/to/dlv user@server:/usr/local/bin/dlv
2. 编译服务端二进制
不要 strip 调试符号。
# 正确
go build -o myapp
# 错误(丢失调试信息)
go build -ldflags="-s -w" -o myapp
CGO 交叉编译示例:
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 \
CC="zig cc -target x86_64-linux-gnu" \
go build -o myapp.linux
部署到服务器,覆盖原文件并重启服务。
3. 挂载 Delve
# 找到目标进程
ps -ef | grep myapp
# 挂载 dlv
dlv attach <PID> --headless --listen=:2345 --api-version=2
看到 API server listening at: [::]:2345 即成功。
注意事项:
- 不加
--log,日志刷屏会导致 dlv 不稳定 - 端口可自定义,后续配置需同步修改
- 确认端口监听:
netstat -tlnp | grep <port>
4. SSH 隧道
在开发机新开终端将远程端口映射到本地。
ssh -NL <本地端口>:localhost:<远程端口> user@server
示例:
ssh -NL 2345:localhost:2345 root@192.168.0.158
先启动 dlv,再开隧道。无报错即成功。
5. VS Code 配置
{
"version": "0.2.0",
"configurations": [
{
"name": "Remote Debug",
"type": "go",
"request": "attach",
"mode": "remote",
"port": 2345,
"host": "localhost"
}
]
}
| 字段 | 说明 |
|---|---|
| host | 走 SSH 隧道,填 localhost |
| port | 与 dlv --listen 端口一致 |
| remotePath | 开发机与服务器源码路径不同时设置 |
"remotePath": "/server/project/path"
6. 调试步骤
- 服务器运行
dlv attach <PID> --headless --listen=:2345 --api-version=2 - 开发机运行
ssh -NL 2345:localhost:2345 user@server - VS Code 按 F5,状态栏变橙色表示连接成功
- 下断点,触发逻辑,开始调试
7. 常见问题
dlv 端口监听但马上消失
杀掉重试:kill -9 <dlv_pid> 再重新挂载。
SSH 隧道 Connection refused
检查服务器 dlv 是否在监听:netstat -tlnp | grep <port>。
断点不生效
- 确认二进制用同一份源码编译
- 确认编译时没有
-ldflags="-s -w" - 重新编译部署
No module detected 日志 Go 1.24+ 正常日志,不影响调试。
8. 备选:本地调试
如果服务器数据库可从开发机访问,可将二进制拉到本地运行:
{
"name": "Local Debug",
"type": "go",
"request": "attach",
"mode": "local",
"processId": <PID>
}
原因:dlv 没在跑、端口不对、或防火墙拦截。
排查:
# 服务器上检查
netstat -tlnp | grep <端口>
ps -ef | grep dlv
Q: 断点不生效(蓝色/灰色,不变橙色)
- 确认二进制用同一份源码编译(git commit 一致)
- 确认编译时没有
-ldflags="-s -w" - 重新编译部署并重试
Q: "No module detected" 日志
Go 1.24+ 下 dlv 的正常日志,针对标准库包的提示,不影响调试。
Q: 端口被占用
换一个即可:
# 服务器
dlv attach <PID> --headless --listen=:3333 --api-version=2
# 开发机 SSH 隧道
ssh -NL 3333:localhost:3333 user@<服务器IP>
# launch.json
"port": 3333
8. 备选方案:本地调试
条件:服务器上的数据库/中间件能从开发机访问。
把二进制拉到本地运行,本地 attach:
{
"name": "Local Debug",
"type": "go",
"request": "attach",
"mode": "local",
"processId": <PID>
}
适用于远程 dlv 不稳定或网络延迟较高的情况。 dlv attach --headless --listen=:2345 --api-version=2
### SSH 隧道显示 "Connection refused"
原因:dlv 没在跑,或端口被占用。
排查:
```bash
# 服务器上确认 dlv 状态
netstat -tlnp | grep 2345
ps -ef | grep dlv
断点不生效(蓝色/灰色状态)
- 确认二进制是用同一份源码编译的
- 确认
-s -w没有被使用(strip 会去掉调试信息) - 尝试重新编译部署
"No module detected" 日志
这是 dlv 在 Go 1.24+ 下的正常日志,针对标准库包的提示,不影响调试。
8. 备选方案:本地调试
如果远程 dlv 不稳定,可以把 Linux 二进制拉到 Windows 本地跑(前提是能连上服务器的 Redis/MySQL),用本地 dlv attach:
{
"name": "Local Debug",
"type": "go",
"request": "attach",
"mode": "local",
"processId": <PID>
}