橡皮擦擦

Golang编译二进制文件后在Alpine内找不到文件的问题

Golang,解决方案

在Alpine 3.7的容器镜像内,执行二进制文件提示not found。
解决方法:

GOOS=linux CGO_ENABLED=0 go build $(RACE) -tags netgo -o bin/gocron ./cmd/gocron

原因分析
本身Go是静态编译的, 对于CGO, 如果设置CGO_ENABLED=0,则完全静态编译,不会再依赖动态库。

如果设置CGO_ENABLED=0,并且你的代码中使用了标准库的net包的话,有可能编译好的镜像无法运行,报sh: /app: not found的错误,尽管/app这个文件实际存在,并且如果讲基础镜像换为centos或者ubuntu的话就能执行。
这是一个奇怪的错误,原因在于:

默认情况下net包会使用静态链接库, 比如libc。

知道了原因,解决办法也很简单,就是完全静态链接或者在基础镜像中加入libc库。

下面是几种解决办法:

设置 CGO_ENABLED=0
编译是使用纯go的net: go build -tags netgo -a -v
使用基础镜像加glibc(或等价库musl、uclibc), 比如 busybox:glibc、alpine + RUN apk add --no-cache libc6-compat、frolvlad/alpine-glibc
有的同学说了,我代码中确实必须使用CGO,因为需要依赖一些C/C++的库。目前没有对应的Go库可替代, 那么可以使用-extldflags "-static",go tool link help介绍了extldflags的功能:

-extldflags flags
Set space-separated flags to pass to the external linker.

-static means do not link against shared libraries

基础镜像
其实前面已经列出了一些常用的基础镜像:

scratch: 空的基础镜像,最小的基础镜像
busybox: 带一些常用的工具,方便调试, 以及它的一些扩展busybox:glibc
alpine: 另一个常用的基础镜像,带包管理功能,方便下载其它依赖的包
显然。 你应该只在编译阶段使用Go的镜像,这样才能将你的镜像减小到最小。

原文来自:《创建最小的Go docker 镜像》

点我评论
打赏本文
二维码


45

文章

6

分类