如何使用vscode远程debug项目

2020.06.14 记录

vscode 的 golang 插件最近开始由 golang 官方维护,插件的 debug 功能(尤其是remote debug)还处于不完善的阶段,配置文件最近有过几次改动。不能用的话要多参考下官方文档:

https://github.com/golang/vscode-go/blob/master/docs/debugging.md

下面是目前的最佳实践配置和一些文档相关的解释。

远端启动

这一节是根据我公司内部的项目结构和生产环境配置来的,领会精神即可。重点是下面的本地配置章节。

项目的 docker/debug.dockerfile 里面要这样配置 entrypoint:

1
ENTRYPOINT ["/dlv", "--log", "--accept-multiclient", "-l=:40000", "--headless=true", "--api-version=2", "exec", "/app"]

解释:

--accept-multiclient 可以让客户端 dlv 多次连接和断开

--api-version=2 是一定要配置的,否则默认是 1

PS: --continue 参数需要测试,可以让 dlv 启动的时候就运行 /app,目前需要连接一次才会启动

k8s deploy.yml 里需要接的 /app 的参数则是(grpc staging 为例):

1
2
3
4
5
- args:
- --
- grpcsvc
- --env
- staging

另外建议 deploy 里把 health check 去掉,内存至少给个 200m。

本地配置

1. vscode 的 luanch.json

1
2
3
4
5
6
7
8
9
{
"name": "Connect to server",
"type": "go",
"request": "attach",
"mode": "remote",
"remotePath": "/builds/infra/service/learning",
"port": 40000,
"host": "localhost"
}

详细解释在最下方。

2. 映射 pod 端口到本地

  1. 应用端口,比如 grpc 为启动时监听的 6000 端口
  2. dlv 启动时监听的端口 40000

pod 会有 log 显示 dlv 连接、创建断点等等行为

3. 把 go mod 的下载目录软链接到仓库目录

比如我本地默认的 GOPATH 是 ~/go,默认 go mod 的下载目录是 ~/go/pkg/mod,那么在仓库根目录(比如 ~/proj/learning)操作:

1
2
mkdir -p .cache/pkg
ln -s ~/go/pkg/mod/ .cache/pkg/mod

这些完成后就可以用 vscode 打断点调试了。

解释

remotePath

这个参数实际上指的是远端运行的二进制在编译时的路径

比如名为 learning 的项目在我们的 gitlab runner 上编译时,当时路径为 /builds/infra/service/learning

这个路径可以在本机 dlv connect 127.0.0.1:40000 后,用 sources 命令查看所有包找到(会列出全部的包,需要搜索一下找到)。

映射关系

vscode 会根据 remotePath 参数和本地的仓库目录计算根目录,映射时去掉不重复的前缀。

2020.06.14 经测试 goland 会很智能的映射文件,但有时还是会出错,比如遇到我们 replace 过的库。

vscode 经过正确映射可以不出错,官方也在尝试加入自动映射文件

软链接

上面这样配置之后,可以正确映射出项目仓库里的文件,我们可以跳转和打断点到正确的行数。

但是这时 go mod 下载目录里的第三方库的代码是没办法调试的。

这是因为 build 出的二进制会记录代码的位置和行数。比如用到 github.com/shanbay/[email protected] 这个库:

  • 在我本地的位置是 ~/go/pkg/mod/github.com/shanbay/[email protected]/
  • gitlab runner 上 build 镜像时,为了缓存第三方库,所以我们把 GOPATH 配置成了相对路径 .cache。所以二进制记录的位置是 /builds/infra/service/learning/.cache/pkg/mod/github.com/shanbay/[email protected]/

在调试的时候 step in 或者打断点,都会没办法映射到本地的文件。vscode 暂时也没有提供一个参数映射 go mod 位置(但是有人提过了)。

所以我们这里给了一个软链接,软链接之后 learning/.cache/pkg/mod/github.com/shanbay/[email protected]/ 目录在本地也存在,所以就能够正常调试了。

标准库同理,我在本地的标准库默认位置是 /usr/local/go/src,gitlab runner 上 build 时标准库也在这个目录,所以不用软连接也可以正确调试和打断点。

所以远端调试,最方便的方法是在远端运行本地 build 出来的 debug 二进制,这样映射关系不用配置就是正确的。