Go编译的二进制文件不会在Ubuntu主机上的高山Docker容器中运行


78

给定一个二进制文件,使用Go使用GOOS=linuxand编译该二进制文件,并将其GOARCH=amd64部署到docker基于的容器中alpine:3.3,如果Docker引擎主机为Ubuntu(15.10),则该二进制文件将不会运行:

sh: /bin/artisan: not found

如果将docker引擎主机(作为的基础)部署在Mac OS X上的VirtualBox VM中,则该相同的二进制文件(针对相同的OS和Arch编译)将运行良好busyboxalpine

如果容器基于Ubuntu映像之一,则同样的二进制文件也可以很好地运行。

知道这个二进制文件丢失了什么吗?

这是我所做的复制操作(未显示在OS X的VirtualBox / busybox中成功运行):

构建(即使拱门匹配,也将使用标志显式构建):

➜  artisan git:(master) ✗ GOOS=linux GOARCH=amd64 go build

检查它是否可以在主机上运行:

➜  artisan git:(master) ✗ ./artisan 
10:14:04.925 [ERROR] artisan: need a command, one of server, provision or build 

复制到docker dir,构建并运行:

➜  artisan git:(master) ✗ cp artisan docker/build/bin/        
➜  artisan git:(master) ✗ cd docker 
➜  docker git:(master) ✗ cat Dockerfile 
FROM docker:1.10
COPY build/ /
➜  docker git:(master) ✗ docker build -t artisan .
Sending build context to Docker daemon 10.15 MB
Step 1 : FROM docker:1.10
...
➜  docker git:(master) ✗ docker run -it artisan sh
/ # /bin/artisan 
sh: /bin/artisan: not found

现在将图像库更改为phusion/baseimage

➜  docker git:(master) ✗ cat Dockerfile 
#FROM docker:1.10
FROM phusion/baseimage
COPY build/ /
➜  docker git:(master) ✗ docker build -t artisan .
Sending build context to Docker daemon 10.15 MB
Step 1 : FROM phusion/baseimage
...
➜  docker git:(master) ✗ docker run -it artisan sh
# /bin/artisan
08:16:39.424 [ERROR] artisan: need a command, one of server, provision or build 

4
添加CGO_ENABLED = 0有帮助吗?
马丁·加拉格尔

魔术,确实如此。请您详细说明一下,我会接受的。
Oleg Sklyar,2016年

您能否go build -tags netgo -a -v std以CGO_ENABLED = 1尝试?我认为这可能是网络软件包的问题,​​导致了动态链接。
马丁·加拉格尔

如您所说,这很有帮助CGO_ENABLED=1 go build -tags netgo -a -v。如果与CGO_ENABLED = 0相比我理解正确,那么这还将在网络软件包中保留TLS功能,否则将丢失该功能,对吗?我能以某种方式看到静态链接到二进制文件的内容以及动态链接剩下的内容吗?
Oleg Sklyar's

2
默认情况下,CGO可以用于net软件包-使用上面的标签或CGO_ENABLED = 0强制使用Go std实现进行查找-您可以执行的操作:ldd output.bin在每个构建变体上查看它们是否真正静态编译或是否存在任何动态链接。
Martin Gallagher

Answers:


92

默认情况下,如果使用该net软件包,则内部版本可能会生成带有某些动态链接(例如到libc)的二进制文件。您可以通过查看以下结果来动态检查静态链接ldd output.bin

我遇到了两种解决方案:

  • 通过禁用CGO CGO_ENABLED=0
  • 强制使用net依赖项netgo的Go实现go build -tags netgo -a -v,这是针对某些平台实现的

https://golang.org/doc/go1.2

默认情况下,net软件包要求使用cgo,因为主机操作系统通常必须中介网络调用设置。但是,在某些系统上,可以使用不带cgo的网络,这样做很有用,例如,避免动态链接。新的构建标签netgo(默认情况下为off)允许在可能的系统上以纯Go格式构建net软件包。

上面假设唯一的CGO依赖项是标准库的net程序包。


3
CGO_ENABLED=0还解决了我的问题:尝试在非高山docker上运行高山内置的go程序。就我而言,错误只是说docker: Error response from daemon: Container command not found or does not exist..
Vlad A. Ionescu

对于使用Bazel的任何人,上述操作都可以通过--features=static --features=pure标志来完成。
本·埃尔加

感谢您提供此答案,因此在Google上进行了大量查找。
凯尔·吉本斯

我认为另一种可选解决方案是将源代码复制到image中,然后exec在image中进行构建。
g10guang

CGO_ENABLED = 0应该可以解决该问题。这个条件也很重要,GOARCH = amd64
Naren Yellavula

64

我在使用go二进制文件时遇到了同样的问题,将其添加到我的docker文件后,它就可以工作了:

RUN apk add --no-cache \ libc6-compat


1
帮助我在我的高山图像中运行CGO
xsor

节省了很多时间。+1
Manwal

1
不幸的是,这对我不起作用,并且给error relocating ...: fprintf chk: symbol not found
TheDiveO

1
您需要在相同的环境中构建和运行。例如,如果您在本地计算机中构建二进制文件并在
docker中

1
我正在Alpine docker容器中运行别人的go二进制文件,我不想自己重新编译它。我宁愿使用公开可用的二进制文件。此解决方案解决了该问题,并让我在Alpine docker容器中运行go二进制文件
Brandon

9

来自构建机器的Go编译器可能会将您的二进制文件与库中的库链接在一起,而不是在Alpine中。在我的情况下,它是使用/ lib64下的依赖项编译的,但是Alpine不使用该文件夹。

FROM alpine:edge AS build
RUN apk update
RUN apk upgrade
RUN apk add --update go=1.8.3-r0 gcc=6.3.0-r4 g++=6.3.0-r4
WORKDIR /app
ENV GOPATH /app
ADD src /app/src
RUN go get server # server is name of our application
RUN CGO_ENABLED=1 GOOS=linux go install -a server

FROM alpine:edge
WORKDIR /app
RUN cd /app
COPY --from=build /app/bin/server /app/bin/server
CMD ["bin/server"]

我正在撰写有关此问题的文章。您可以在http://kefblog.com/2017-07-04/Golang-ang-docker上找到具有此解决方案的草稿。


3

对我来说,诀窍是在链接器选项中启用静态链接:

$ go build -ldflags '-linkmode external -w -extldflags "-static"'

-linkmode选项告诉Go使用外部链接器,该-extldflags选项设置将选项传递给链接器,并且该-w标志禁用DWARF调试信息以提高二进制大小。

即使使用cgo,也可以始终使用musl查看go tool link静态编译的Go程序,以 获取更多详细信息


0

在debian docker容器内执行go二进制文件时,遇到此问题: /bin/bash: line 10: /my/go/binary: No such file or directory

二进制文件是通过使用以下命令从高山容器中使用docker-in-docker(dind)构建的: GOOS=linux GOARCH=amd64 go build

在构建二进制文件时使用以下env修复了此问题: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.