英文:
Debug Golang in containers with delve: container_linux.go:380: starting container process caused: exec: "/dlv": stat /dlv: no such file or directory
问题
我正在尝试将我自己的 Golang 调试版本应用程序与 Golang 调试工具 delve 一起容器化。以下是我如何在本地调试我的 Golang 应用程序的步骤,它是一个非常简单的 RSS 阅读器,从我感兴趣的 RSS 源中获取数据。
在我的本地终端上执行以下命令来使用 delve 调试我的 Golang 应用程序:
$ dlv debug parsedata-xml-fp.go # 使用 delve 启动我的应用程序
Type 'help' for list of commands.
(dlv) b main
Command failed: Location "main" ambiguous: main.main, runtime.main…
(dlv) b main.main
Breakpoint 1 set at 0x760252 for main.main() ./parsedata-xml-fp.go:50
(dlv) c
> main.main() ./parsedata-xml-fp.go:50 (hits goroutine(1):1 total:1) (PC: 0x760252)
=> 50: func main() {
51: // [decode from response.Body]
52: url := "https://foreignpolicy.com/feed/"
53:
54: var URLset Rss
55: if xmlBytes, err := getXML(url); err != nil {
(dlv) l
> main.main() ./parsedata-xml-fp.go:50 (hits goroutine(1):1 total:1) (PC: 0x760252)
=> 50: func main() {
51: // [decode from response.Body]
52: url := "https://foreignpolicy.com/feed/"
53:
54: var URLset Rss
55: if xmlBytes, err := getXML(url); err != nil {
(dlv)
在我的本地机器上,我可以设置断点并进入我感兴趣的函数。
我尝试在我构建的容器内做同样的事情。
选项1:
以下是我的容器的 Dockerfile:
# Dockerfile.dlv
FROM golang:1.17 AS build
WORKDIR /
COPY go/app/parsedata-xml-fp.go .
COPY go.mod .
COPY go.sum .
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -gcflags="all=-N -l" -o /feedme
RUN echo $(ls /go/bin)
# stage 2 build
FROM ubuntu:18.04
WORKDIR /
EXPOSE 2345
COPY --from=build /go/bin/dlv /dlv
COPY --from=build /feedme /feedme
COPY --from=build /parsedata-xml-fp.go /parsedata-xml-fp.go
CMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/feedme"]
当我启动容器并登录时,我遇到了以下错误:
exec: "go": 在 $PATH 中找不到可执行文件
以下是我容器中的完整日志:
sudo docker exec -it b1494552ef1d /bin/sh
# which dlv
# ls
bin dev etc home lib64 mnt parsedata-xml-fp.go root sbin sys usr
boot dlv feedme lib media opt proc run srv tmp var
# ./dlv
Delve is a source level debugger for Go programs.
......... # 忽略 delve 的帮助信息,只是确认 delve 已安装
Use "dlv [command] --help" for more information about a command.
# ./dlv debug parsedata-xml-fp.go
exec: "go": 在 $PATH 中找不到可执行文件
# which go
# (什么都没有显示)
我的理解是 ubuntu1804 没有安装 go。然后我尝试只使用 golang 的 Docker 镜像。
选项2:
更新的 Dockerfile 如下:使用 golang:1.17 作为基础镜像(Go 应该已经安装):
# Dockerfile.localmod
FROM golang:1.17 AS build
WORKDIR /
COPY go/app/parsedata-xml-fp.go .
COPY go.mod .
COPY go.sum .
RUN echo $(which shell)
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -gcflags="all=-N -l" -o /feedme
RUN echo $(ls /go/bin)
EXPOSE 2345
CMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/feedme"]
这次错误发生在我启动容器时:
sudo docker run 734129d1b1a2
docker: 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.
ERRO[0000] error waiting for container: context canceled
有人能建议如何正确地将 delve 集成到我的 Go 容器中,并在容器终端上进行调试,就像在本地调试一样吗?
英文:
I am trying to containerize a debug version Golang application of my own with Golang debugging delve build in.
Here is how I can debug my Golang application locally , it is a very simple RSS reader. It retrieves data from RSS feed I am interested in.
$on my local terminal$ dlv debug parsedata-xml-fp.go # launch my app with delve
Type 'help' for list of commands.
(dlv) b main
Command failed: Location "main" ambiguous: main.main, runtime.main…
(dlv) b main.main
Breakpoint 1 set at 0x760252 for main.main() ./parsedata-xml-fp.go:50
(dlv) c
> main.main() ./parsedata-xml-fp.go:50 (hits goroutine(1):1 total:1) (PC: 0x760252)
=> 50: func main() {
51: // [decode from response.Body]
52: url := "https://foreignpolicy.com/feed/"
53:
54: var URLset Rss
55: if xmlBytes, err := getXML(url); err != nil {
(dlv) l
> main.main() ./parsedata-xml-fp.go:50 (hits goroutine(1):1 total:1) (PC: 0x760252)
=> 50: func main() {
51: // [decode from response.Body]
52: url := "https://foreignpolicy.com/feed/"
53:
54: var URLset Rss
55: if xmlBytes, err := getXML(url); err != nil {
(dlv)
On my local machine I can set breakpoints and step into functions I am interested in.
I was trying to do the same inside a container I built.
Option #1:
Below is the Dockerfile of my container
#Dockerfile.dlv
FROM golang:1.17 AS build
WORKDIR /
COPY go/app/parsedata-xml-fp.go .
COPY go.mod .
COPY go.sum .
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -gcflags="all=-N -l" -o /feedme
RUN echo $(ls /go/bin)
# stage 2 build
FROM ubuntu:18.04
WORKDIR /
EXPOSE 2345
COPY --from=build /go/bin/dlv /dlv
COPY --from=build /feedme /feedme
COPY --from=build /parsedata-xml-fp.go /parsedata-xml-fp.go
CMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/feedme"]
When bootup my container and login , I go the error :
exec: "go": executable file not found in $PATH
Below is the complete log in my containter
sudo docker exec -it b1494552ef1d /bin/sh
# which dlv
# ls
bin dev etc home lib64 mnt parsedata-xml-fp.go root sbin sys usr
boot dlv feedme lib media opt proc run srv tmp var
# ./dlv
Delve is a source level debugger for Go programs.
......... # dismiss delve help info , just to confirm dlv is installed
Use "dlv [command] --help" for more information about a command.
# ./dlv debug parsedata-xml-fp.go
exec: "go": executable file not found in $PATH
# which go
# (nothing)
My understanding is ubuntu1804 has no go installed ? Then I tried to use go docker image only
Option #2
Updated Dockerfile as below : use golang:1.17 as base image (Go should be there):
# Dockerfile.localmod
FROM golang:1.17 AS build
WORKDIR /
COPY go/app/parsedata-xml-fp.go .
COPY go.mod .
COPY go.sum .
RUN echo $(which shell)
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go build -gcflags="all=-N -l" -o /feedme
RUN echo $(ls /go/bin)
EXPOSE 2345
CMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/feedme"]
This time error occurred right at I boot my container
sudo docker run 734129d1b1a2
docker: 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.
ERRO[0000] error waiting for container: context canceled
Anyone could suggest what is the right way of intergrate delve into my Go container and debugging it on container terminal exactly as debug locally?
答案1
得分: 4
问题出在你的dlv
二进制文件被动态编译了。当你使用go install
下载二进制文件时,默认情况下会使用CGO_ENABLED=1
(除非被覆盖),这要求大部分运行时库(包括glibc)在运行时加载。这在某些容器镜像中可能无法正常工作,因为这些库可能不存在(例如从头构建的镜像或无发行版的静态镜像)。
为了避免与容器镜像的依赖关系,可以通过将上述标志设置为0来始终下载静态编译的二进制文件。在你的Docker上下文中使用下载的二进制文件。
CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest
你还可以观察静态和动态编译版本的dlv
上的ldd
输出。前者不会列出需要动态加载的任何库,而后者会列出这些库。
英文:
The problem is with your dlv
binary being dynamically compiled. When you download the binary with go install
, by default it downloads with CGO_ENABLED=1
(unless overriden), requiring most of the runtime libraries (including glibc) to be loaded at runtime. This might not work well in some container images, where the libraries are not present (e.g. images built from scratch/distro-less static images).
So to avoid the dependency with the container image's dependencies, always download a statically compiled one by setting the above flag to 0. Use the downloaded binary in your docker context
CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest
You can also observe the ldd
output on dlv
between the statically and dynamically compiled versions. The former would list no libraries that would need to be dynamically loaded, the latter would list them.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论