使用Goland + Air + Delve进行远程调试Docker环境
你好,我是神山,在Trada担任服务器端工程师。
这是Toreta Advent Calendar第12天的文章。
在这篇文章中,我想要介绍一下在docker-compose环境中使用golang进行远程调试的方法。
简述
使用Docker Compose来搭建Golang环境,并在其中运行应用程序。
由于已经使用air的热重载功能,可以立即反映差异,所以我可以放心地进行开发。
但随着服务代码量的增加和需求的复杂化,逐渐变得难以调试。
因此,我尝试引入delve来进行调试。
环境
-
- MacBook Pro(Apple M1)
-
- go version go1.19.4 linux/arm64
-
- Docker Compose version v2.13.0
-
- air v1.40.4
- delve v1.20.1
docker-compose.yml的中文意思是什么?
我编写了以下的docker-compose文件。
version: '3.7'
services:
app:
image: 'golang:1.19'
working_dir: '/app'
volumes:
- type: bind
source: '.'
target: '/app'
ports:
- '8080:8080'
- '2345:2345'
command: >
sh -c '
go install github.com/go-delve/delve/cmd/dlv@latest
go install github.com/cosmtrek/air@latest
air -c .air.toml
'
-
- imageはそのままgolangの1.19を指定しています。
-
- working_dirにソースコードをbindしています。
-
- portsは二箇所開けています。
api用の8080
リモートデバッグ接続用の2345
commandでdocker-composeをbuildするタイミングでdelveとairををinstall、airを起動するようにしています。
本記事では触れませんが、本番環境用に別でDockerfileを用意しています。
本番環境ではdelve, airともにinstallしたくないのでここに記載する形にしました。
.air.toml 我只需要一个选项在中文中的表达方式
如果正在使用Air,我认为您已创建了一个toml文件。
我只编辑了下面所述的部分,其他部分未更改。
[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -gcflags \"all=-N -l\" -o ./.air/main ./cmd/main.go"
# Binary file yields from `cmd`.
bin = "./.air/main"
# Customize binary.
full_bin = "APP_ENV=dev APP_USER=air dlv exec ./.air/main --headless=true --listen=:2345 --api-version=2 --accept-multiclient"
cmdでは、./cmd/main.goをbuildして、./.air/mainにバイナリを配置しています。
binでは、あらためてバイナリの位置を記載しています。
full_binでは、airコマンドを使ってdelve用のserverを起動します。
在这种情况下,运行docker-compose up应该会在终端上显示以下日志。
app | API server listening at: [::]:2345
app | 2022-12-19T10:16:59Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
远程调试连接
-
- golandの右上からEdit Configurationを選択します。
+ボタンからGo Remoteを選択してください。
Nameは適当な名前を入れてください。
Hostはlocalhost, Portは2345を指定してください。
Leave it runnningにチェックを入れて保存してください。

- 下記のような表示になっているはずなので、デバッグマークを押してください。

- 問題なければ下記のようにConnectedが表示されるはずです。

尝试进行调试
我为此准备了一个main函数,与原始代码完全不同。通过GET http://localhost:8080/hello访问,只会返回响应。
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello", helloHandler)
http.ListenAndServe(":8080", nil)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
test := "Hello Remote Debug!!"
fmt.Fprint(w, test)
}
我会在实际环境中设置断点并调用API进行测试。
您可以在下方的调试控制台中看到test变量的值等信息。
如果您修改并保存源代码,热重载也会有效。

1. 留意事项
2. 注意要点
3. 注意事项
4. 注意细节
5. 注意重点
看起来在M1 Mac上使用指定为linux/amd64的docker环境无法使用delve调试工具。
具体来说,我将docker-compose.yml修改如下:
由于golang1.19不支持linux/amd64镜像,我将其修改为golang:1.19-buster。
version: '3.7'
services:
app:
+ platform: 'linux/amd64'
+ image: 'golang:1.19-buster'
- image: 'golang:1.19'
working_dir: '/app'
volumes:
- type: bind
source: '.'
target: '/app'
ports:
- '8080:8080'
- '2345:2345'
command: >
sh -c '
go install github.com/go-delve/delve/cmd/dlv@latest
go install github.com/cosmtrek/air@latest
air -c .air.toml
'
在其他设置保持不变的情况下,执行docker-compose up。
尽管可以启动,但出现了”无法启动进程:fork/exec /app/.air/main: 功能未实现”的错误提示。
app | API server listening at: [::]:2345
app | 2022-12-19T10:37:43Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
app | could not launch process: fork/exec /app/.air/main: function not implemented
当我调查delve的问题时,发现了这个问题。
https://github.com/go-delve/delve/issues/2910
我们对此无能为力。
评论会议已经关闭了,没有人理会。太无情了。
最后
虽然有点勉强,但我已经使用delve实现了远程调试。
由于在生产环境的Dockerfile中使用了linux/amd64的golang:1.19-buster,所以我认为不能完全信赖这个调试环境。
然而,当团队成员提出评论或编写复杂逻辑时,没有调试是很困难的……
在这种情况下,只需要稍微更改docker-compose.yml和.air.toml文件,就可以构建远程调试环境,非常方便。
特别是golang这种语言经常需要像for循环这样的直接写法,所以将开发体验进行优化能提高效率呢。。
另外,请注意,在我们这里正在招聘工程师。
如果你有兴趣,请务必联系我们。