波波技术栈
article

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. 调试步骤

  1. 服务器运行 dlv attach <PID> --headless --listen=:2345 --api-version=2
  2. 开发机运行 ssh -NL 2345:localhost:2345 user@server
  3. VS Code 按 F5,状态栏变橙色表示连接成功
  4. 下断点,触发逻辑,开始调试

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>
}