Alpine镜像中not found引出的gnu libc和musl libc的争论_alpine /lib/ld-musl-x86_64.so.1: cannot load java:-程序员宅基地

在一个使用旧版的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
 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Michaelwubo/article/details/105443286

智能推荐

后端配置(宝塔):SSH终端设置_宝塔ssh密钥登录-程序员宅基地

本文介绍了Future接口的主要作用是用于异步处理任务,并列举了其中的方法。同时展示了运行结果,说明了futureTask.get()方法需要5秒才能返回结果,导致主线程被阻塞了5秒。

计算机考试金麦圈编号教程,计算机二级:数据处理-程序员宅基地

文章浏览阅读7.6k次。《计算机二级:数据处理》由会员分享,可在线阅读,更多相关《计算机二级:数据处理(10页珍藏版)》请在人人文库网上搜索。1、精品文库打开 Excelkt 文件夹下的 Excel14A.xlsx 工作簿文件,按下列要求操作。1、基本编辑 将Exceikt文件夹下的ScoreA.docx文件中的数据复制到Sheetl工作表A2单元格开始 处。 编辑 Sheet1 工作表A. 在最左端插入 1列,列宽10..._公式填充商品编号,商品名称有金麦圈

360路由器的虚拟服务器设置,360路由器无线万能中继设置教程图解-程序员宅基地

文章浏览阅读2.1k次。如果WiFi在很久之前就出现了,皇宫也准备安装路由器该怎么办?首先需要通过两个关卡的考验。第一关:【安全】惜命的皇上夸张到每道菜都要找专人试毒,面对有着无限可能,潜藏着DNS劫持和钓鱼网站等诸多陷阱的网络世界,安全自然是最为重要的。考虑到360安全路由有9大安全防护秘籍,过关!第二关:【信号覆盖】封建社会,为了凸显皇权的至高无上,必然会要求整个皇宫只能皇上自己使用主路由,而后妃等不能僭越。这就产生..._360路由器p4g无线中续

虎牙直播网页弹幕过滤小探索_虎牙弹幕脚本js-程序员宅基地

文章浏览阅读703次。虎牙直播网页弹幕过滤小探索没过滤前,一堆 333过滤后,舒服了js代码使用方法网页看直播时候,没发现有过滤弹幕的功能,自己摸索了一下。没过滤前,一堆 333过滤后,舒服了js代码 //过滤内容 var filterKeyWord= '333'; $("#danmudiv").unbind("DOMNodeInserted"); $("#chat-room__list").unbind("DOMNodeInserted"); /** * 清理弹幕 _虎牙弹幕脚本js

Java 自定义注解及注解读取解析--模拟框架生成SQL语句_* 1.读取类中的注解信息 *2.根据注解中包含的建表结构信息创建sql语句ja* 3.使用j-程序员宅基地

文章浏览阅读247次。Java 自定义注解及注解读取解析--模拟框架生成SQL语句假设们使用一张简单的表,结构如下:定义注解:表注解:package com.xzlf.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.la..._* 1.读取类中的注解信息 *2.根据注解中包含的建表结构信息创建sql语句ja* 3.使用j

GDKOI 2021 提高组 Day1 第三题 回文(manachar+ST表)_gdkoi2021 day1t3-程序员宅基地

文章浏览阅读175次。GDKOI 2021 提高组 Day1 第三题 回文题目大意给出长为nnn的串,和qqq组询问,每次询问区间中的最长回文串。n,q≤5∗105n,q\le5*10^5n,q≤5∗105题解可以先用manachar求出以每个位置为中心的回文串,询问时二分答案,然后在区间中判断是否存在长度为midmidmid的回文串,用ST表维护区间最值。注意二分判断时并非在整个区间[l,r][l,r][l,r]中找最大值,而需分别将左端点右移和右端点左移大约midmidmid(因奇偶而不同)的位置,以保证找_gdkoi2021 day1t3

随便推点

pythonTensor Flow预测数据_python tensorflow 预测下一组数据-程序员宅基地

文章浏览阅读789次。通过载入csv表格数据,创建数据模型,实现梯度递减,对数据进行预测#导入tensorflowimport tensorflow as tf#导入excel处理模块import pandas as pdimport numpy as nb#导入数据可视化模块 pyplot:图形绘制模块import matplotlib.pyplot as mpl数据载入data = pd.read_csv('yq.csv')x = nb.array(data.get('date'))y = nb.a_python tensorflow 预测下一组数据

使用a标签创建引入js中的方法_a标签导入外部js-程序员宅基地

文章浏览阅读704次。1. a href="javascript:js_method();" 这是平台上常用的方法,但是这种方法在传递this等参数的时候很容易出问题,而且javascript:协议作为a的href属性的时候不仅会导致不必要的触发window.onbeforeunload事件,在IE里面更会使gif动画图片停止播放。W3C标准不推荐在href里面执行javascript语句 2. a h_a标签导入外部js

小程序怎么自定义导航栏,导航栏放图片、设置高度_小程序自定义导航栏-程序员宅基地

文章浏览阅读1.1w次,点赞4次,收藏28次。这样就搞定了,希望你们的logo比我的好看。今天来说一下小程序的自定义导航栏。_小程序自定义导航栏

Introduction to Robotics 总结1~6-程序员宅基地

文章浏览阅读6.8k次,点赞4次,收藏32次。机器人学中经典教材 《Introduction to Robotics: Mechanics and Control》,也就是John Craig的中文版《机器人学导论》,刚来实验室的时候,就发现师兄们人手一本了,某些章节自己啃也是有点难度的,之前在 Youtube上看完了斯坦福 Oussama Khatib 教授的视频Introduction to Robotics,他们上课使用的教材就是这本,一共十六篇lecture,讲解也是很通俗易懂,涵盖了机器人坐标变化、D-H参数建模、动力学、运动学、PD、PI._introduction to robotics

【HDU3038】How Many Answers Are Wrong(带权并查集)_tt and ff are ... friends. uh... very very good fr-程序员宅基地

文章浏览阅读146次。题目链接 How Many Answers Are Wrong Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 15260 Accepted Submission(s): 5361 Proble..._tt and ff are ... friends. uh... very very good friends -________-b ff is a

库文件整理-程序员宅基地

文章浏览阅读110次。纸上得来终觉浅,绝知此事要躬行。C系统提供了丰富的系统文件,称为库文件。C的库文件分为两类,一类是扩展名为‘.h’的文件,称为头文件。在该类文件中包含了常量的定义、类型定义、宏定义、函数原型及各种编译选择设置等信息。另一类是库函数,包含了各种函数的目标代码,供用户在程序中调用。通常在程序中调用一个库函数时,要在调用之前包含该函数原型所在的.h文件。alloc.h 内存管理..._库文件整理

推荐文章

热门文章

相关标签