在一个使用旧版的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: 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中给得到了解决,由于没有热闹可看,请读者自行阅读

使用的相关内容在这里:

简单来说,解决的方法就是在Alpine里面安装glibc,让Alpine不再是Alpine

看完热闹,现在花1分钟快速解决一下遗留问题。重新回到问题现场。按照如下三步骤进行安装

  • 步骤1: 下载key
~ # wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
~ # echo $?
~ # 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

在一个使用旧版的Oracle的JDK的Alpine版本的镜像时出现了问题,这篇文章作为后续的整理,以此为契机,简单介绍一下Alpine版本中的musl libc和gnu libc的设定。
Go语言虽然是平台无关性的语言,但是构建出来的应用由于是可执行文件,所以注定无法像Java那样“一次编译、处处运行”,因为Java应用程序的二进制字节码下的解释由JVM这一层来实现,所以能够实现一次编译之后随处运行的平台无关性。这篇文章通过Alpine下编译的二进制文件的运行方式来说明在实际使用需要注意的一个细节。 使用Alpine构建Go应用 Go提供官方镜像用于构建Go语言的应用,官方镜像也包括Alpine镜像。如何使用Docker镜像构建Go语言应用可参看: https://liumiaocn.blog.csdn.net/article/details/103778750
肌肉LFS Linux From Scratch,使用Musl作为Libc和S6 + S6-rc作为初始化系统 这是基于Linux From Scratch( )的工作,该工作使用GLibc和SysVinit / systemD。 其他工作来自Void Linux( ),Alpine Linux( )和Dragora Linux( )。 为了在开发工具链期间进行日志记录,我使用了porg。 该项目的目的是使用Musl( )代替GNU的Glibc和S6( )创建一个Linux系统,而不是SysVinit。 支持的架构 i686 / i586:稳定且经过测试。 足够稳定,可以构建Xorg,Qt5(无QT-webengine),Rust和Firefox。 x86_64:稳定且经过测试。 足够稳定以构建Xorg,Qt5,Rust和Firefox。 aarch64:稳定且经过测试
再者,alpine支持sh 而不是bash 步骤1: 下载key ~ # wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub 步骤2: 下载apk安装文件 wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2
问题描述: 现场环境下的镜像包无法确定部分源码,需要通过arthas监控查询代码。arthas需要基于jps寻找java进程,但是该镜像jdk为openjdk没有jps命令。复制hotspot jdk镜像执行java -jar arthas-boot.jar ./bin/java: not found 以为是权限的问题,chmod 777 java之后还是not found。 在服务器内执行 ldd java 查看java所需的动态链库 [root@bin
编译通过,程序简单运行easy_init()时报错 no version information available curl是额外编译源码获得的,与系统不同,此处问题的解决办法类似如下 解决 libcurl.so.4: no version information available | 云梦 https://www.htcp.net/3766.html 小巧:基于Musl libc和busybox,和busybox一样小巧,最小的Docker镜像只有5MB; 安全:面向安全的轻量发行版; 简单:提供APK包管理工具,软件的搜索、安装、删除、升级都非常方便。 适合容器使用:由...
报错:relocation error: /usr/lib64/libc.so.6: symbol _dl_starting_up, version GLIBC_PRIVA not defined i