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

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

sh: /bin/artisan: not found

如果 docker 引擎主机是部署在 Mac OS X 上的 VirtualBox VM 中的 busybox(这是 alpine的基础) ,那么这个相同的二进制文件(为相同的 OS 和 arch 编译)将是 跑得很好

如果容器是基于某个 Ubuntu 映像的,那么这个二进制文件也可以很好地运行。

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

下面是我复制的内容(没有显示在 VirtualBox/busybox 上的成功运行) :

Build (使用标志显式构建,即使拱形匹配) :

➜  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 目录,构建,运行:

➜  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
52471 次浏览

By default, if using the net package a build will likely produce a binary with some dynamic linking, e.g. to libc. You can inspect dynamically vs. statically link by viewing the result of ldd output.bin

There are two solutions I've come across:

  • Disable CGO, via CGO_ENABLED=0
  • Force the use of the Go implementation of net dependencies, netgo via go build -tags netgo -a -v, this is implemented for a certain platforms

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

The net package requires cgo by default because the host operating system must in general mediate network call setup. On some systems, though, it is possible to use the network without cgo, and useful to do so, for instance to avoid dynamic linking. The new build tag netgo (off by default) allows the construction of a net package in pure Go on those systems where it is possible.

The above assumes that the only CGO dependency is the standard library's net package.

Go compiler from your build machine probably links your binary with libraries on different location than in Alpine. In my case it was compiled with dependencies under /lib64 but Alpine does not use that folder.

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"]

I'm working on article about this issue. You can find draft with this solution here http://kefblog.com/2017-07-04/Golang-ang-docker .

I had the same issue with a go binary, and I got it to work after adding this to my docker file:

RUN apk add --no-cache libc6-compat

What did the trick for me was enabling static linking in the linker options:

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

The -linkmode option tells Go to use the external linker, the -extldflags option sets options to pass to the linker and the -w flag disables DWARF debug info to improve binary size.

See go tool link and Statically compiled Go programs, always, even with cgo, using musl for more details

While executing a go binary inside a debian docker container, faced this issue: /bin/bash: line 10: /my/go/binary: No such file or directory

The binary was built by using docker-in-docker (dind) from an alpine container using command: GOOS=linux GOARCH=amd64 go build

Fixed it by using following env while building the binary: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build

I had an app that required CGO_ENABLED=1.

The fix for me to run the compiled go binary in a debian-slim container was to build the binary using RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o goapp

And run the following commands in the debian slim

RUN apt-get update && apt-get install -y musl-dev
RUN ln -s /usr/lib/x86_64-linux-musl/libc.so /lib/libc.musl-x86_64.so.1

Made me able to run the goapp afterwards

TIP: ldd goapp showed that libc.musl-x86_64 was missing in the container.