英文:
Can't execute go binary with docker multi stage build
问题
我尝试按照以下方式构建Go应用程序,我的main.go文件位于cmd/app/main.go。
然而,当我尝试运行docker build --no-cache .
和docker run <container_id>
时,它给出了exec ./bin/app: no such file or directory
的错误。
我已经测试过运行go build -o ./bin/app ./cmd/app
和./bin/app
是可以正常运行的。
这是我的Dockerfile:
# Build phase
FROM golang:1.20 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download && go mod verify
COPY . .
RUN go build -o ./bin/app ./cmd/app
# Production phase
FROM alpine:3.14
WORKDIR /app
COPY --from=builder /app/bin/app ./bin/app
ENTRYPOINT ["./bin/app"]
我尝试进入容器docker run -it -t fyno/server/multi /bin/sh
/app # cd bin
/app/bin # ls -la
total 11636
drwxr-xr-x 2 root root 4096 Apr 12 05:04 .
drwxr-xr-x 1 root root 4096 Apr 12 05:04 ..
-rwxr-xr-x 1 root root 11904381 Apr 12 05:04 app
/app/bin # ./app
/bin/sh: ./app: not found
/app/bin #
谢谢。
如何解决这个问题?
英文:
I try to build the go app as follow, my main.go file is at cmd/app/main.go.
However, when I try running docker build --no-cache .
and docker run <container_id>
.
It gives me exec ./bin/app: no such file or directory
I've already test that running go build -o ./bin/app ./cmd/app
and ./bin/app
is able to run correctly.
Here is my Dockerfile
# Build phase
FROM golang:1.20 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download && go mod verify
COPY . .
RUN go build -o ./bin/app ./cmd/app
# Production phase
FROM alpine:3.14
WORKDIR /app
COPY --from=builder /app/bin/app ./bin/app
ENTRYPOINT [ "./bin/app" ]
I tried to access into the container docker run -it -t fyno/server/multi /bin/sh
/app # cd bin
/app/bin # ls -la
total 11636
drwxr-xr-x 2 root root 4096 Apr 12 05:04 .
drwxr-xr-x 1 root root 4096 Apr 12 05:04 ..
-rwxr-xr-x 1 root root 11904381 Apr 12 05:04 app
/app/bin # ./app
/bin/sh: ./app: not found
/app/bin #
Thanks.
how to fix the problem?
答案1
得分: 1
首先,路径存在一些问题,导致出现了“没有该文件或目录”的错误。我写了一个简单的Dockerfile
示例,并将导致混淆的app
二进制文件重命名,因为在你的示例中它位于一个名为app
的目录中。希望现在更清楚了。
其次,在修复Dockerfile
中路径不准确的问题后,你遇到了一个更微妙的问题,即尝试运行Go二进制文件时出现“找不到”,因为golang构建器镜像使用的是“Debian GLIBC 2.31-13+deb11u5 2.31”,而运行镜像使用的是“musl libc (x86_64) Version 1.2.2”。
最简单的解决方法是在构建时设置CGO_ENABLED=0
。如果你真的想使用cgo
进行编译,请找到在这方面兼容的构建器和运行镜像。有关类似问题的几种替代方案和解决方法,请参考这里。
第三,你在评论中提到了.env
文件,所以我在MVP中还包含了一个简单的读取和显示使用docker run --env ...
注入的环境变量。
以下是示例代码:
.
├── cmd
│ └── main.go
├── Dockerfile
├── go.mod
└── go.sum
Dockerfile:
# Build phase
FROM golang:1.20 AS builder
# Next line is just for debug
RUN ldd --version
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download && go mod verify
COPY . .
WORKDIR /build/cmd
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o go-binary
# Production phase
FROM alpine:3.14
# Next line is just for debug
RUN ldd; exit 0
WORKDIR /app
COPY --from=builder /build/cmd/go-binary .
ENTRYPOINT ["/app/go-binary"]
main.go:
package main
import (
"os"
"time"
"github.com/rs/zerolog/log"
)
func main() {
yourVar := os.Getenv("YOUR_VAR")
for {
time.Sleep(time.Second)
log.Info().Msg(yourVar)
}
}
构建和运行命令:
docker build --no-cache -t stack-overflow-go-docker:v1.0 .
docker run --env YOUR_VAR=your-value stack-overflow-go-docker:v1.0
输出结果:
{"level":"info","time":"2023-04-14T21:12:37Z","message":"your-value"}
{"level":"info","time":"2023-04-14T21:12:38Z","message":"your-value"}
英文:
First, there are some problems with the paths, causing your no such file or directory error.
I wrote a minimal Dockerfile
example and renamed the app
binary which was causing confusion because it was located in an app
directory in your example. I hope it makes more sense now.
Second, after fixing the paths inaccuracies in the Dockerfile
, you run into a more subtle problem, when trying to run the go binary: not found, because the the golang builder image is using Debian GLIBC 2.31-13+deb11u5 2.31 while the runner image is using musl libc (x86_64)
Version 1.2.2.
The easiest fix is to set CGO_ENABLED=0
when building. If you really want to use cgo
to compile, find a builder and a runner images that are compatible in this regard.
Several alternatives and workarounds are provided for a similar question here.
Third, you also mentioned about the .env
file in a comment so I also included in the MVP a simple read-display for an environment variable injected with docker run --env ...
.
.
├── cmd
│ └── main.go
├── Dockerfile
├── go.mod
└── go.sum
Dockerfile:
# Build phase
FROM golang:1.20 AS builder
# Next line is just for debug
RUN ldd --version
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download && go mod verify
COPY . .
WORKDIR /build/cmd
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o go-binary
# Production phase
FROM alpine:3.14
# Next line is just for debug
RUN ldd; exit 0
WORKDIR /app
COPY --from=builder /build/cmd/go-binary .
ENTRYPOINT [ "/app/go-binary"]
main.go:
package main
import (
"os"
"time"
"github.com/rs/zerolog/log"
)
func main() {
yourVar := os.Getenv("YOUR_VAR")
for {
time.Sleep(time.Second)
log.Info().Msg(yourVar)
}
}
Build and run:
docker build --no-cache -t stack-overflow-go-docker:v1.0 .
docker run --env YOUR_VAR=your-value stack-overflow-go-docker:v1.0
{"level":"info","time":"2023-04-14T21:12:37Z","message":"your-value"}
{"level":"info","time":"2023-04-14T21:12:38Z","message":"your-value"}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论