Dockerfile问题 – 为什么找不到二进制文件dlv – 没有这个文件或目录

huangapple go评论89阅读模式
英文:

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 来检查并查看镜像中是否有位于路径 /dlvdlv,结果发现确实有。我还附上了一张图片:

Dockerfile问题 – 为什么找不到二进制文件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

Dockerfile问题 – 为什么找不到二进制文件dlv – 没有这个文件或目录

答案1

得分: 2

你在alpine-based的发行版中构建了dlvdlv可执行文件链接到了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

按照以下步骤进行操作:

  1. docker run -it <image-name> sh
  2. apt-get install file
  3. 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:

  1. docker run -it <image-name> sh
  2. apt-get install file
  3. 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.

huangapple
  • 本文由 发表于 2022年10月30日 12:47:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/74250570.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定