无法使用Docker多阶段构建执行Go二进制文件。

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

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 &lt;container_id&gt;.
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 &amp;&amp; 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 [ &quot;./bin/app&quot; ]

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 &amp;&amp; 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 [ &quot;/app/go-binary&quot;]

main.go:

package main

import (
	&quot;os&quot;
	&quot;time&quot;

	&quot;github.com/rs/zerolog/log&quot;
)

func main() {
	yourVar := os.Getenv(&quot;YOUR_VAR&quot;)
	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
{&quot;level&quot;:&quot;info&quot;,&quot;time&quot;:&quot;2023-04-14T21:12:37Z&quot;,&quot;message&quot;:&quot;your-value&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;time&quot;:&quot;2023-04-14T21:12:38Z&quot;,&quot;message&quot;:&quot;your-value&quot;}

huangapple
  • 本文由 发表于 2023年4月12日 12:47:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75991985.html
匿名

发表评论

匿名网友

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

确定