CI阶段使用的镜像size要尽可能地小,这样在CI pull时使用的时间也会相应的短,所以有些base镜像都是基于alpine编译出来的
今天在alpine
的base
镜像中使用mongoimport
时,提示了not fuond
的奇怪问题,记录一下解决过程
alpine
使用的镜像为最新的alpine:1.13
, mongoimport
为官方使用go 1.15编译出来的二进制文件
Dockfile
文件如下:
1 | FROM alpine/git:latest |
镜像编译完成之后运行起来后,会提示以下的错误:
1 | main.sh: workflow.sh: line 133: mongoimport: not found |
not found
这个很奇怪,我开始以为是没有找到mongoimport
这个命令,但使用ls或者which
后发现在/usr/bin
是存在mongoimport
但这个not found
指的是什么呢?
一番google
后发现在使用alpine
时,如果按正常的go编译命令编译出来的二进制文件或多或少地地出现这个问题,原因是什么呢?
这个就要从alpine
使用的musl libc说起,而对应的则是gnu libc,这两者有什么区别呢?
gnu libc
是标准的libc的库,我们大部分时间编译出来的都是可以使用这个库
而Alpine采用了
musl libc和
busybox` 以减小系统的体积和运行时资源消耗
所以用alpine做base的镜像体积非常的小, 很适合用于CI阶段
musl libc只能说是部分兼容`gnu libc,因此也不是所有的go编译出来的二进制都无法使用
这两者详细的区别大家可考虑这些链接:
https://blog.csdn.net/liumiaocn/article/details/89702529
回到问题本身,上面提示not found
是不是也是因为mongoimport
编译的时候使用的是动态库,要怎么解决呢?
从网上的解决方案来看,有以下几种解决方案:
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
- RUN apk –no-cache add libc6-compat libgcc libstdc++
- go编译时指定
CGO_ENABLED=0 go build .
第一种方式我尝试过,可惜,可以解决not found
的报错,也就是说可以找到二进制命令了,但是命令中如果引用了其它的动态库,则还是会有问题,会提示如下的报错:
1 | Error loading shared library libgssapi_krb5.so.2: No such file or directory (needed by /usr/bin/mongoimport) |
开始的时候为了保证镜像的size尽可能的小,还打算将错误提示中的so手工放到镜像中,考虑后续不可维护,就没有再尝试
对于方式2我也尝试了,libc6-compat
是libc的兼容包, 大部分提示not found
的问题都可以通过安装这个包进行解决,本人未解决
由于mongodb官方提供的tools版本没有基于alpine可用的,对于方式3本人未尝试,原因在于mongodb-tools
提供的编译工具相对比较麻烦, 而且我只是需要一个mongoimport
,官方的编译工具没办法只编译mongoimpmort
,理论来说指定CGO_ENABLED=0
编译出来的二进制是可用的
本人使用最后一种方式,这里偷机了一把, 随便run一个alpine的镜像,然后在镜像中add mongodb-tools
,最后在/usr/bin/mongoimport
这单个二进制复制出来,然后放到base镜像中,这样避免直接在base中安装,降低size
之前网上就看到要慎用alpine,会出现各种各样奇怪的问题, 看来是真的