Go 编译的二进制文件不会 运行 在 Ubuntu 主机上的高山 docker 容器中
Go-compiled binary won't run in an alpine docker container on Ubuntu host
给定一个二进制文件,使用 GOOS=linux
和 GOARCH=amd64
用 Go 编译,部署到基于 alpine:3.3
的 docker
容器,二进制文件不会 运行 如果 docker 引擎主机是 Ubuntu (15.10):
sh: /bin/artisan: not found
如果 docker 引擎主机是busybox
(这是 alpine
的基础)部署在 Mac OS X 上的 VirtualBox VM 中。
如果容器基于 Ubuntu 个图像之一,那么这个二进制文件也 运行 完全没问题。
知道这个二进制文件丢失了什么吗?
这是我为重现所做的(在 OS X 未显示 VirtualBox/busybox 中成功 运行):
构建(即使 arch 匹配也明确地使用标志构建):
➜ 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
默认情况下,如果使用 net
包,构建可能会生成带有一些动态 linking 的二进制文件,例如到 libc。您可以通过查看 ldd output.bin
的结果来动态检查与静态检查 link
我遇到过两种解决方案:
- 禁用 CGO,通过
CGO_ENABLED=0
- 强制使用 net 依赖项的 Go 实现,netgo via
go build -tags netgo -a -v
,这是为特定平台实现的
来自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.
以上假定唯一的 CGO 依赖项是标准库的 net
包。
您构建机器上的 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 .
我在使用 go 二进制文件时遇到了同样的问题,将其添加到我的 docker 文件后我就可以正常工作了:
RUN apk add --no-cache libc6-compat
我的诀窍是在链接器选项中启用静态链接:
$ go build -ldflags '-linkmode external -w -extldflags "-static"'
-linkmode
选项告诉 Go 使用外部链接器,-extldflags
选项设置传递给链接器的选项,-w
标志禁用 DWARF 调试信息以改善二进制大小.
查看go tool link
和静态编译的Go程序,总是,即使使用cgo,使用musl
了解更多详情
在 debian docker 容器中执行 go 二进制文件时,遇到了这个问题:
/bin/bash: line 10: /my/go/binary: No such file or directory
二进制文件是使用命令从 alpine 容器中使用 docker-in-docker (dind) 构建的:
GOOS=linux GOARCH=amd64 go build
在构建二进制文件时通过使用以下环境修复了它:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
我有一个应用需要 CGO_ENABLED=1
。
我对 运行 在 debian-slim 容器中编译的 go 二进制文件的修复是使用 RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o goapp
构建二进制文件
和运行在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
让我能够 运行 之后的 goapp
提示:ldd goapp
显示容器中缺少 libc.musl-x86_64。
给定一个二进制文件,使用 GOOS=linux
和 GOARCH=amd64
用 Go 编译,部署到基于 alpine:3.3
的 docker
容器,二进制文件不会 运行 如果 docker 引擎主机是 Ubuntu (15.10):
sh: /bin/artisan: not found
如果 docker 引擎主机是busybox
(这是 alpine
的基础)部署在 Mac OS X 上的 VirtualBox VM 中。
如果容器基于 Ubuntu 个图像之一,那么这个二进制文件也 运行 完全没问题。
知道这个二进制文件丢失了什么吗?
这是我为重现所做的(在 OS X 未显示 VirtualBox/busybox 中成功 运行):
构建(即使 arch 匹配也明确地使用标志构建):
➜ 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
默认情况下,如果使用 net
包,构建可能会生成带有一些动态 linking 的二进制文件,例如到 libc。您可以通过查看 ldd output.bin
我遇到过两种解决方案:
- 禁用 CGO,通过
CGO_ENABLED=0
- 强制使用 net 依赖项的 Go 实现,netgo via
go build -tags netgo -a -v
,这是为特定平台实现的
来自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.
以上假定唯一的 CGO 依赖项是标准库的 net
包。
您构建机器上的 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 .
我在使用 go 二进制文件时遇到了同样的问题,将其添加到我的 docker 文件后我就可以正常工作了:
RUN apk add --no-cache libc6-compat
我的诀窍是在链接器选项中启用静态链接:
$ go build -ldflags '-linkmode external -w -extldflags "-static"'
-linkmode
选项告诉 Go 使用外部链接器,-extldflags
选项设置传递给链接器的选项,-w
标志禁用 DWARF 调试信息以改善二进制大小.
查看go tool link
和静态编译的Go程序,总是,即使使用cgo,使用musl
了解更多详情
在 debian docker 容器中执行 go 二进制文件时,遇到了这个问题:
/bin/bash: line 10: /my/go/binary: No such file or directory
二进制文件是使用命令从 alpine 容器中使用 docker-in-docker (dind) 构建的:
GOOS=linux GOARCH=amd64 go build
在构建二进制文件时通过使用以下环境修复了它:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
我有一个应用需要 CGO_ENABLED=1
。
我对 运行 在 debian-slim 容器中编译的 go 二进制文件的修复是使用 RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o goapp
和运行在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
让我能够 运行 之后的 goapp
提示:ldd goapp
显示容器中缺少 libc.musl-x86_64。