如何用 VSCode 调试 Docker Compose 中的 Go 测试?
结论
在 test 镜像阶段安装 Delve(dlv),让容器通过 Delve 启动测试,再让 VSCode 以远程调试模式连接 Delve。当前 test 阶段基于 base,而 base 中没有安装 dlv。另外,docker compose run 默认不会发布服务中声明的端口,因此需要加上 --service-ports。
配置测试容器
在 Dockerfile 的 test 阶段安装 Delve,并将容器命令改为使用 dlv test 启动测试:
FROM base AS test
RUN go install github.com/go-delve/delve/cmd/dlv@latest
COPY go.* ./
RUN go mod download
COPY . .
CMD ["/go/bin/dlv", "test", "./...", "--headless", "--listen=:2345", "--api-version=2", "--accept-multiclient"]
dlv test 会构建并运行 Go 测试程序。--headless 启动无界面的调试服务,--listen=:2345 让容器在 2345 端口监听,--accept-multiclient 允许调试客户端连接。只调试某个包时,可以将 ./... 替换为对应的包路径。需要传递测试参数时,在 Delve 参数后加上 --,再写测试参数,例如 -- -test.run TestExample。
在 Compose 的 test 服务中发布调试端口,并为调试器授予所需的 ptrace 权限:
test:
build:
context: .
target: test
volumes:
- .:/app
- gomodcache:/go/pkg/mod
env_file: .env
depends_on:
- db
ports:
- "40535:2345"
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
这里将宿主机的 40535 端口映射到容器的 2345 端口。启动调试容器时运行:
docker compose run --service-ports test
使用旧版 Compose 命令时,也可以运行 docker-compose run --service-ports test。--service-ports 会发布 Compose 服务中声明的端口。启动后让终端和容器保持运行,等待 VSCode 连接。
配置 VSCode 远程调试
在项目的 .vscode/launch.json 中添加以下配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Go tests in Docker",
"type": "go",
"request": "attach",
"mode": "remote",
"host": "127.0.0.1",
"port": 40535,
"substitutePath": [
{
"from": "${workspaceFolder}",
"to": "/app"
}
]
}
]
}
在 VSCode 中选择 Attach to Go tests in Docker 并启动调试。substitutePath 会将容器内的 /app 路径映射到本地工作区,否则 VSCode 可能无法将容器中的源码位置对应到本地文件。
断点与注意事项
先在本地测试文件中设置断点,再启动容器并连接调试器。测试运行结束后,Delve 不会自动重新运行测试;需要停止并重新启动测试容器。
配置中的 SYS_PTRACE 和 seccomp:unconfined 用于允许 Delve 在容器中跟踪 Go 测试进程。如果容器运行环境不允许这些权限,调试器可能无法启动或跟踪进程。若测试依赖数据库,确保数据库已就绪。当前的 depends_on: - db 只声明启动依赖,没有配置等待健康检查通过。
备注:内容仅供参考。
