使用 delve 在容器中调试 Golang:container_linux.go:380: 启动容器进程导致:exec: "/dlv": stat /dlv: 没有这样的文件或目录

Jia*_*Jia 7 containers go docker delve

我正在尝试使用 Golang 调试深入构建来容器化我自己的调试版本 Golang 应用程序。\n这是我如何在本地调试我的 Golang 应用程序,它是一个非常简单的 RSS 阅读器。它从我感兴趣的 RSS 提要中检索数据。

\n
$on my local terminal$ dlv debug parsedata-xml-fp.go  # launch my app with delve\nType 'help' for list of commands.\n(dlv) b main\nCommand failed: Location "main" ambiguous: main.main, runtime.main\xe2\x80\xa6\n(dlv) b main.main\nBreakpoint 1 set at 0x760252 for main.main() ./parsedata-xml-fp.go:50\n(dlv) c\n> main.main() ./parsedata-xml-fp.go:50 (hits goroutine(1):1 total:1) (PC: 0x760252)\n=>  50: func main() {\n    51:         // [decode from response.Body]\n    52:         url := "https://foreignpolicy.com/feed/"\n    53:\n    54:         var URLset Rss\n    55:         if xmlBytes, err := getXML(url); err != nil {\n(dlv) l\n> main.main() ./parsedata-xml-fp.go:50 (hits goroutine(1):1 total:1) (PC: 0x760252)\n=>  50: func main() {\n    51:         // [decode from response.Body]\n    52:         url := "https://foreignpolicy.com/feed/"\n    53:\n    54:         var URLset Rss\n    55:         if xmlBytes, err := getXML(url); err != nil {\n(dlv) \n
Run Code Online (Sandbox Code Playgroud)\n

在我的本地计算机上,我可以设置断点并单步执行我感兴趣的函数。

\n

我试图在我构建的容器内做同样的事情。

\n

选项1: \n下面是我的容器的 Dockerfile

\n
#Dockerfile.dlv\nFROM golang:1.17 AS build\n\nWORKDIR /\nCOPY go/app/parsedata-xml-fp.go .\nCOPY go.mod .\nCOPY go.sum .\n    \nRUN go install github.com/go-delve/delve/cmd/dlv@latest\nRUN go build -gcflags="all=-N -l" -o /feedme\nRUN echo $(ls /go/bin)\n\n# stage 2 build \nFROM ubuntu:18.04\nWORKDIR /\n\nEXPOSE 2345 \n\nCOPY --from=build /go/bin/dlv /dlv\nCOPY --from=build /feedme /feedme\nCOPY --from=build /parsedata-xml-fp.go /parsedata-xml-fp.go\nCMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/feedme"]\n
Run Code Online (Sandbox Code Playgroud)\n

当启动我的容器并登录时,出现错误:

\n
exec: "go": executable file not found in $PATH\n
Run Code Online (Sandbox Code Playgroud)\n

以下是我的容器中的完整日志

\n
sudo docker exec -it b1494552ef1d /bin/sh\n# which dlv\n# ls\nbin   dev  etc     home  lib64  mnt  parsedata-xml-fp.go  root  sbin  sys  usr\nboot  dlv  feedme  lib   media  opt  proc                 run   srv   tmp  var\n# ./dlv\nDelve is a source level debugger for Go programs.\n  ......... # dismiss delve help info , just to confirm dlv is installed \n\nUse "dlv [command] --help" for more information about a command.\n# ./dlv debug parsedata-xml-fp.go\nexec: "go": executable file not found in $PATH\n# which go\n# (nothing)\n
Run Code Online (Sandbox Code Playgroud)\n

我的理解是ubuntu1804没有安装go?然后我尝试仅使用 go docker image

\n

选项#2

\n

更新的 Dockerfile 如下:使用golang:1.17作为基础镜像(Go 应该在那里):

\n
# Dockerfile.localmod\nFROM golang:1.17 AS build\n\nWORKDIR /\nCOPY go/app/parsedata-xml-fp.go .\nCOPY go.mod .\nCOPY go.sum .\n\nRUN echo $(which shell)\n\nRUN go install github.com/go-delve/delve/cmd/dlv@latest\nRUN go build -gcflags="all=-N -l" -o /feedme\nRUN echo $(ls /go/bin)\n\nEXPOSE 2345 \nCMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/feedme"]\n
Run Code Online (Sandbox Code Playgroud)\n

这次错误发生在我启动容器时

\n
sudo docker run 734129d1b1a2                     \ndocker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "/dlv": stat /dlv: no such file or directory: unknown.\nERRO[0000] error waiting for container: context canceled\n
Run Code Online (Sandbox Code Playgroud)\n

任何人都可以建议什么是集成深入到我的 Go 容器并在容器终端上调试它的正确方法,就像本地调试一样?

\n

Ini*_*ian 6

问题在于您的dlv二进制文件是动态编译的。当您使用 下载二进制文件时go install,默认情况下它会下载CGO_ENABLED=1(除非覆盖),需要在运行时加载大多数运行时库(包括 glibc)。这在某些不存在库的容器映像中可能无法正常工作(例如从头开始构建的映像/无发行版静态映像)。

因此,为了避免与容器镜像的依赖关系,请始终通过将上述标志设置为 0 来下载静态编译的镜像。在 docker 上下文中使用下载的二进制文件

CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest
Run Code Online (Sandbox Code Playgroud)

您还可以观察静态编译版本和动态编译版本之间的ldd输出。dlv前者不会列出需要动态加载的库,后者会列出它们。