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

Ole*_*yar 54 go busybox docker alpine-linux

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

sh: /bin/artisan: not found
Run Code Online (Sandbox Code Playgroud)

如果在Mac OS X上的VirtualBox VM中部署了docker引擎主机(它是基础),那么相同的二进制文件(针对相同的OS和arch编译)将运行得很好.busyboxalpine

如果容器基于Ubuntu映像之一,那么同样的二进制文件也将完美运行.

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

这是我为重现而做的(在OS X上的VirtualBox/busybox中成功运行未显示):

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

?  artisan git:(master) ? GOOS=linux GOARCH=amd64 go build
Run Code Online (Sandbox Code Playgroud)

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

?  artisan git:(master) ? ./artisan 
10:14:04.925 [ERROR] artisan: need a command, one of server, provision or build 
Run Code Online (Sandbox Code Playgroud)

复制到docker目录,构建,运行:

?  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
Run Code Online (Sandbox Code Playgroud)

现在将图像库更改为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 
Run Code Online (Sandbox Code Playgroud)

Mar*_*her 66

默认情况下,如果使用net包,则构建可能会生成带有一些动态链接的二进制文件,例如libc.您可以通过查看结果来动态检查静态链接ldd output.bin

我遇到过两种解决方案:

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

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

默认情况下,网络包需要cgo,因为主机操作系统通常必须调解网络呼叫设置.但是,在某些系统上,可以使用没有cgo的网络,这样做很有用,例如避免动态链接.新的构建标签netgo(默认情况下是关闭)允许在可能的系统上构建纯Go的网络包.

以上假设唯一的CGO依赖是标准库的net包.

  • `CGO_ENABLED = 0`也解决了我的问题:试图在非高山码头上运行高山建造的程序.我的案例中的错误只是说`docker:来自守护进程的错误响应:未找到容器命令或不存在.` (2认同)

zak*_*ine 46

我有一个go二进制文件的问题,我把它添加到我的docker文件后得到了它的工作:

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

  • 节省了很多时间。+1 (2认同)
  • 不幸的是,这对我不起作用,并给出了`错误重定位......:fprintf chk:找不到符号` (2认同)

小智 8

从构建机器转到编译器可能会将您的二进制文件链接到与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"]
Run Code Online (Sandbox Code Playgroud)

我正在撰写关于这个问题的文章.你可以在http://kefblog.com/2017-07-04/Golang-ang-docker找到这个解决方案的草稿.


msi*_*ens 6

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

$ go build -ldflags '-linkmode external -w -extldflags "-static"'
Run Code Online (Sandbox Code Playgroud)

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

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