Alpine镜像中not found引出的gnu libc和musl libc的争论

在一个使用旧版的Oracle的JDK的Alpine版本的镜像时出现了问题,这篇文章作为后续的整理,以此为契机,简单介绍一下Alpine版本中的musl libc和gnu libc的设定。

事前准备
运行alpine容器
准备一个Alpine镜像,这里使用3.9的版本,并将Alpine容器运行起来,容器名为alpine

liumiaocn:multibytes liumiao$ docker run --name alpine --rm -it alpine:3.9 sh
/ # 


准备可执行文件
这里准备旧版的JDK,取7u79,并将其拷贝至alpine容器的/tmp目录下

liumiaocn:Desktop liumiao$ docker cp jdk-7u79-linux-x64.tar.gz alpine:/tmp
liumiaocn:Desktop liumiao$


解压JDK至/usr/local/share/java

/ # cd /tmp
/tmp # ls
jdk-7u79-linux-x64.tar.gz
/tmp # 
/tmp # mkdir -p /usr/local/share/java
tar xzf jdk-7u79-linux-x64.tar.gz -C /usr/local/share/java
/tmp # cd /usr/local/share/java
/usr/local/share/java # ls
jdk1.7.0_79
/usr/local/share/java #


现象
JDK只需要设定可执行目录至PATH搜索范围中即可,设定之后发现使用which可以找到java可执行文件,但是执行java -version却提示java not found, 所以现象的提示显得非常诡异。

~ # export PATH=$PATH:/usr/local/share/java/jdk1.7.0_79/bin
~ # which java
/usr/local/share/java/jdk1.7.0_79/bin/java
~ # 
~ # java -version
sh: java: not found
~ #


ldd错误
动态连接库错误,ldd提示信息如下所示

~ # which java
/usr/local/share/java/jdk1.7.0_79/bin/java
~ # ldd /usr/local/share/java/jdk1.7.0_79/bin/java
	/lib64/ld-linux-x86-64.so.2 (0x7f5c1184c000)
	libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f5c1184c000)
	libjli.so => /usr/local/share/java/jdk1.7.0_79/bin/../lib/amd64/jli/libjli.so (0x7f5c11635000)
	libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7f5c1184c000)
	libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f5c1184c000)
Error relocating /usr/local/share/java/jdk1.7.0_79/bin/../lib/amd64/jli/libjli.so: __rawmemchr: symbol not found
~ #


原因与对应
ldd错误看起来好像是jli的的relocating提示错误信息,而实际上由于Alpine镜像使用的根本不是gnu libc而是musl libc,所以/lib64/ld-linux-x86-64.so.2是不存在的,而实际上/lib64都是不存在的。

~ # ls /lib64

~ # ls /lib64
ls: /lib64: No such file or directory
~ #


gnu libc和musl libc号称兼容(部分兼容),基于缺什么补什么的原则,做个软链补上即可(stack overflow也有人有同样方法进行过验证)。由于Oracle的Java并不是完整的源码提供,所以Alpine也无法拿到源码去全编译来解决这个问题,大概这就是在Alpine镜像中更多的是OpenJDK的原因。

~ # mkdir /lib64
~ # ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
~ #


这个问题一旦得到对应,现象就不再诡异,再次执行java命令,中规中矩地提示了缺少的动态链接库

~ # java -version
Error relocating /usr/local/share/java/jdk1.7.0_79/bin/../lib/amd64/jli/libjli.so: __rawmemchr: symbol not found
~ # 


gnu libc和musl libc的争论
顺这个问题在Alpine的issue中很快找到了一个几年前的issue,写的很详细,jirutka 小哥还提到了Alpine的3S(Small/Simple/Secure)哲学,并坚持认为不应该在Alpine里面添加对于gnu libc的支持, 以下为轻松时间,可以顺便学点,学不到也完全不要紧,我们主要是坐第一排看热闹。

他们的现象跟本文的现象完全一样不同的是Oracle的JDK8,不同的是非常快得就有人帮着定位出了根本原因,而我查了几个小时

jirutka 小哥说,如果使用Oracle版本的JDK,或者类似需求,你应该去找支持glibc的linux发行版

再次甩给Oracle,该他们管,Alpine的已经有MUSL了,谁用Glibc谁自己负责,另外代码不全部公开Alpine也无能为力。而且还认为,使用了glibc的Alpine就不再是Alpine!是的,会变成奥特曼的

有人提出两个libc能不能一起来用,小哥坚持认为两个libc不是好的方法

专门有人去跟Oracle确认了一下,结论是没有好的办法,不过可以花钱来寻求专业帮助

另外一位小哥总结了一下:要么用指定的所谓的标准版本,像使用Alpine这种非标准方式就只好花钱雇人了

而这些终于在这个issue中给得到了解决,由于没有热闹可看,请读者自行阅读

https://github.com/ibmdb/node-ibm_db/issues/217
使用的相关内容在这里:

https://github.com/sgerrand/alpine-pkg-glibc
简单来说,解决的方法就是在Alpine里面安装glibc,让Alpine不再是Alpine

详细看这个issue
觉得还想看的话,自己去看这个issue
https://github.com/gliderlabs/docker-alpine/issues/11
验证
看完热闹,现在花1分钟快速解决一下遗留问题。重新回到问题现场。按照如下三步骤进行安装

步骤1: 下载key

~ # wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
~ # echo $?
0
~ # ls /etc/apk/keys/sgerrand.rsa.pub
/etc/apk/keys/sgerrand.rsa.pub
~ #


步骤2: 下载apk安装文件

~ # wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.29-r0/glibc-2.29-r0.apk
Connecting to github.com (13.229.188.59:443)
Connecting to github-production-release-asset-2e65be.s3.amazonaws.com (52.216.176.203:443)
glibc-2.29-r0.apk    100% |****************************************************************************************| 2006k  0:00:00 ETA
~ # ls
glibc-2.29-r0.apk
~ #


步骤3: 安装

~ # apk add glibc-2.29-r0.apk
(1/1) Installing glibc (2.29-r0)
OK: 9 MiB in 15 packages
~ # 


虽然ldd不能正常使用,但是实际上已经能够执行了,这是因为设定了RPATH。因为没有readelf命令,这里就不再展示了。

# ldd /usr/local/share/java/jdk1.7.0_79/bin/java
	/lib64/ld-linux-x86-64.so.2 (0x7f83ae582000)
	libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f83ae582000)
	libjli.so => /usr/local/share/java/jdk1.7.0_79/bin/../lib/amd64/jli/libjli.so (0x7f83ae36b000)
	libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7f83ae582000)
	libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f83ae582000)
Error relocating /usr/local/share/java/jdk1.7.0_79/bin/../lib/amd64/jli/libjli.so: __rawmemchr: symbol not found
~ # 


可以看到已经可以正常使用了, ldd对使用者来说,基本就是透明的。先凑合用吧。

~ # java -version
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)
~ #


总结
其实小哥说的对,这种拧着做的方法确实不值得推荐,但毕竟生活有很多无奈,且行且拧吧。

参考文档
https://stackoverflow.com/questions/34729748/installed-go-binary-not-found-in-path-on-alpine-linux-docker
https://github.com/docker-library/openjdk/issues/77
https://github.com/gliderlabs/docker-alpine/issues/11
https://github.com/sgerrand/alpine-pkg-glibc/releases
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值