英文:
Dockerfile issue - Why is the binary dlv not being found - No such file or directory
问题
我有一个正常工作的 Docker 文件。然而,为了进行远程调试,我阅读到需要在其中安装 dlv
,然后运行 dlv 并传递我要调试的应用程序的参数。所以在安装了 dlv 并尝试运行它之后,我得到了以下错误:
exec /dlv: 没有那个文件或目录
这是 Docker 文件的内容:
FROM golang:1.18-alpine AS builder
# 为了调试构建 Delve
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# 创建并切换到应用程序目录。
WORKDIR /app
ENV CGO_ENABLED=0
# 获取应用程序的依赖项。
COPY go.* ./
RUN go mod download
# 将本地代码复制到容器镜像中。
COPY . ./
# 构建二进制文件。
RUN go build -gcflags="all=-N -l" -o fooapp
# 使用官方的 Debian slim 镜像作为精简的生产容器。
FROM debian:buster-slim
EXPOSE 8000 40000
RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
# 从构建阶段将二进制文件复制到生产镜像中。
#COPY --from=builder /app/fooapp /app/fooapp #注释掉了这一行
COPY --from=builder /go/bin/dlv /dlv
# 运行 dlv 并传递 fooapp 作为参数
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/app/fooapp"]
以上代码导致了 exec /dlv: 没有那个文件或目录
的错误。
我不确定为什么会出现这个问题。作为对 Docker 不熟悉的新手,我尝试了不同的调试方法。我尝试使用 dive
来检查并查看镜像中是否有位于路径 /dlv
的 dlv
,结果发现确实有。我还附上了一张图片:
英文:
I had a docker file that was working fine. However to remote debug it , I read that I needed to install dlv
on it and then I need to run dlv and pass the parameter of the app I am trying to debug. So after installing dlv on it and attempting to run it. I get the error
exec /dlv: no such file or directory
This is the docker file
FROM golang:1.18-alpine AS builder
# Build Delve for debugging
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# Create and change to the app directory.
WORKDIR /app
ENV CGO_ENABLED=0
# Retrieve application dependencies.
COPY go.* ./
RUN go mod download
# Copy local code to the container image.
COPY . ./
# Build the binary.
RUN go build -gcflags="all=-N -l" -o fooapp
# Use the official Debian slim image for a lean production container.
FROM debian:buster-slim
EXPOSE 8000 40000
RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
# Copy the binary to the production image from the builder stage.
#COPY --from=builder /app/fooapp /app/fooapp #commented this out
COPY --from=builder /go/bin/dlv /dlv
# Run dlv as pass fooapp as parameter
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/app/fooapp"]
The above results in exec /dlv: no such file or directory
I am not sure why this is happening. Being new to docker , I have tried different ways to debug it. I tried using dive
to check and see if the image has dlv
on it in the path /dlv
and it does. I have also attached an image of it
答案1
得分: 2
你在alpine
-based的发行版中构建了dlv
。dlv
可执行文件链接到了libc.musl
:
# ldd dlv
linux-vdso.so.1 (0x00007ffcd251d000)
libc.musl-x86_64.so.1 => not found
但后来你切换到了基于glibc
的镜像debian:buster-slim
。该镜像没有所需的库:
# find / -name libc.musl*
<nothing found>
这就是为什么你无法执行dlv
的原因 - 动态链接器无法找到正确的库。
你需要在基于glibc
的Docker中构建。例如,将第一行替换为:
FROM golang:bullseye AS builder
顺便说一下,构建后你需要在特权模式下运行容器:
$ docker build . -t try-dlv
...
$ docker run --privileged --rm try-dlv
API server listening at: [::]:40000
2022-10-30T10:51:02Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
在非特权容器中,dlv
不允许生成子进程:
$ docker run --rm try-dlv
API server listening at: [::]:40000
2022-10-30T10:55:46Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
could not launch process: fork/exec /app/fooapp: operation not permitted
真正的最小镜像
你使用debian:buster-slim
来最小化镜像,它的大小为80 MB。但如果你需要一个真正小的镜像,可以使用busybox
,它只有4.86 MB的开销:
FROM golang:bullseye AS builder
# Build Delve for debugging
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# Create and change to the app directory.
WORKDIR /app
ENV CGO_ENABLED=0
# Retrieve application dependencies.
COPY go.* ./
RUN go mod download
# Copy local code to the container image.
COPY . ./
# Build the binary.
RUN go build -o fooapp .
# Download certificates
RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates
# Use the official Debian slim image for a lean production container.
FROM busybox:glibc
EXPOSE 8000 40000
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/fooapp /app/fooapp
# COPY --from=builder /app/ /app
COPY --from=builder /go/bin/dlv /dlv
COPY --from=builder /etc/ssl /etc/ssl
# Run dlv as pass fooapp as parameter
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/app/fooapp"]
# ENTRYPOINT ["/bin/sh"]
镜像大小为25 MB,其中18 MB来自dlv
,2 MB来自Hello World
应用程序。
在选择镜像时,应注意具有相同的libc
版本。golang:bullseye
链接到glibc
。因此,最小化镜像必须基于glibc
。
但如果你想要更多的便利性,可以使用安装了gcompat
软件包的alpine
。它是一个相对丰富的Linux发行版,与busybox
相比只多了6 MB的额外开销:
FROM golang:bullseye AS builder
# Build Delve for debugging
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# Create and change to the app directory.
WORKDIR /app
ENV CGO_ENABLED=0
# Copy local code to the container image.
COPY . ./
# Retrieve application dependencies.
RUN go mod tidy
# Build the binary.
RUN go build -o fooapp .
# Use alpine lean production container.
# FROM busybox:glibc
FROM alpine:latest
# gcompat is the package to glibc-based apps
# ca-certificates contains trusted TLS CA certs
# bash is just for the comfort, I hate /bin/sh
RUN apk add gcompat ca-certificates bash
EXPOSE 8000 40000
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/fooapp /app/fooapp
# COPY --from=builder /app/ /app
COPY --from=builder /go/bin/dlv /dlv
# Run dlv as pass fooapp as parameter
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/app/fooapp"]
# ENTRYPOINT ["/bin/bash"]
英文:
You built dlv
in alpine
-based distro. dlv
executable is linked against libc.musl
:
# ldd dlv
linux-vdso.so.1 (0x00007ffcd251d000)
libc.musl-x86_64.so.1 => not found
But then you switched to glibc
-based image debian:buster-slim
. That image doesn't have the required libraries.
# find / -name libc.musl*
<nothing found>
That's why you can't execute dlv
- the dynamic linker fails to find the proper lib.
You need to build in glibc
-based docker. For example, replace the first line
FROM golang:bullseye AS builder
BTW. After you build you need to run the container in the priviledged mode
$ docker build . -t try-dlv
...
$ docker run --privileged --rm try-dlv
API server listening at: [::]:40000
2022-10-30T10:51:02Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
In non-priviledged container dlv
is not allowed to spawn a child process.
$ docker run --rm try-dlv
API server listening at: [::]:40000
2022-10-30T10:55:46Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
could not launch process: fork/exec /app/fooapp: operation not permitted
Really Minimal Image
You use debian:buster-slim
to minimize the image, it's size is 80 MB. But if you need a really small image, use busybox
, it is only 4.86 MB overhead.
FROM golang:bullseye AS builder
# Build Delve for debugging
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# Create and change to the app directory.
WORKDIR /app
ENV CGO_ENABLED=0
# Retrieve application dependencies.
COPY go.* ./
RUN go mod download
# Copy local code to the container image.
COPY . ./
# Build the binary.
RUN go build -o fooapp .
# Download certificates
RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates
# Use the official Debian slim image for a lean production container.
FROM busybox:glibc
EXPOSE 8000 40000
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/fooapp /app/fooapp
# COPY --from=builder /app/ /app
COPY --from=builder /go/bin/dlv /dlv
COPY --from=builder /etc/ssl /etc/ssl
# Run dlv as pass fooapp as parameter
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/app/fooapp"]
# ENTRYPOINT ["/bin/sh"]
The image size is 25 MB, of which 18 MB are from dlv
and 2 MB are from Hello World
application.
While choosing the images care should be taken to have the same flavors of libc
. golang:bullseye
links against glibc
. Hence, the minimal image must be glibc
-based.
But if you want a bit more comfort, use alpine
with gcompat
package installed. It is a reasonably rich linux with lots of external packages for just extra 6 MB compared to busybox
.
FROM golang:bullseye AS builder
# Build Delve for debugging
RUN go install github.com/go-delve/delve/cmd/dlv@latest
# Create and change to the app directory.
WORKDIR /app
ENV CGO_ENABLED=0
# Copy local code to the container image.
COPY . ./
# Retrieve application dependencies.
RUN go mod tidy
# Build the binary.
RUN go build -o fooapp .
# Use alpine lean production container.
# FROM busybox:glibc
FROM alpine:latest
# gcompat is the package to glibc-based apps
# ca-certificates contains trusted TLS CA certs
# bash is just for the comfort, I hate /bin/sh
RUN apk add gcompat ca-certificates bash
EXPOSE 8000 40000
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/fooapp /app/fooapp
# COPY --from=builder /app/ /app
COPY --from=builder /go/bin/dlv /dlv
# Run dlv as pass fooapp as parameter
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/app/fooapp"]
# ENTRYPOINT ["/bin/bash"]
答案2
得分: 1
TL;DR
运行 apt-get install musl
,然后 /dlv
应该按预期工作。
Explanation
按照以下步骤进行操作:
docker run -it <image-name> sh
apt-get install file
file /dlv
然后你会看到以下输出:
/dlv: ELF 64-bit LSB 可执行文件, x86-64, 版本 1 (SYSV), 动态链接, 解释器 /lib/ld-musl-x86_64.so.1, Go BuildID=xV8RHgfpp-zlDlpElKQb/DOLzpvO_A6CJb7sj1Nxf/aCHlNjW4ruS1RXQUbuCC/JgrF83mgm55ntjRnBpHH, 未剥离
混淆的 no such file or directory
(参见此问题以获取相关讨论)是由于缺少 /lib/ld-musl-x86_64.so.1
引起的。
因此,解决方案是按照musl文档进行安装。
我的答案受到此答案的启发。
英文:
TL;DR
Run apt-get install musl
, then /dlv
should work as expected.
Explanation
Follow these steps:
docker run -it <image-name> sh
apt-get install file
file /dlv
Then you can see the following output:
/dlv: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, Go BuildID=xV8RHgfpp-zlDlpElKQb/DOLzpvO_A6CJb7sj1Nxf/aCHlNjW4ruS1RXQUbuCC/JgrF83mgm55ntjRnBpHH, not stripped
The confusing no such file or directory
(see this question for related discussions) is caused by the missing /lib/ld-musl-x86_64.so.1
.
As a result, the solution is to install the musl
library by following its documentation.
My answer is inspired by this answer.
答案3
得分: 0
no such file or directory
错误表示您的二进制文件不存在,或者您的二进制文件动态链接到一个不存在的库。
根据这个答案所说,Delve是与libc.musl链接的。因此,在构建Delve时,您可以禁用CGO
,因为这可能会导致与libc/libmusl的动态链接:
# 为调试构建Delve
RUN CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest
...
这甚至允许您稍后使用scratch构建您的最终目标镜像,而无需安装任何额外的软件包,如musl
,也不需要使用任何基于glibc
的镜像并要求您以特权模式运行。
英文:
The no such file or directory
error indicates either your binary file does not exist, or your binary is dynamically linked to a library that does not exist.
As said in this answer, delve is linked against libc.musl. So for your delve build, you can disable CGO
since that can result in dynamic links to libc/libmusl:
# Build Delve for debugging
RUN CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest
...
This even allows you later to use a scratch build for your final target image and does not require you to install any additional packages like musl
or use any glibc
based image and require you to run in privileged mode.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论