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

  • 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

Alpine镜像中not found引出的gnu libc和musl libc的争论相关推荐

  1. Alpine镜像中时区的设置

    缺省状态下Alpine镜像下的timezone会设定成UTC,相较于东八区的CST北京时间来说本地时间比UTC早了8个小时.这篇文章介绍一下时区相关的基础知识以及如何在Alpine中将时间从UTC设定 ...

  2. alpine linux中安装docker

    简介 Small. Simple. Secure. Alpine Linux is a security-oriented, lightweight Linux distribution based ...

  3. docker中使用golang:alpine镜像制作开启goweb的dockerfile

    docker中使用golang:alpine镜像制作开启goweb的dockerfile go的web代码 package mainimport("net/http""f ...

  4. Alpine Linux 中的 apk 命令讲解

    Alpine Linux是一个面向安全应用的轻量级Linux发行版.它采用了musl libc和busybox以减小系统的体积和运行时资源消耗,同时还提供了自己的包管理工具apk. 官方帮助文档 al ...

  5. JEECG容器化部署:Alpine镜像方式

    在前面的一篇文章中提到了JEECG的Alpine镜像使用时出现的问题,就是验证码需要使用到fontmanager,而环境中的OPENJDK的JRE中又没有提供,所以退而求其次使用官方的Dockerfi ...

  6. 使用alpine镜像封装nginx 及php镜像

    环境说明 centos 7.6.1810 docker 18.09.7 alpine latest nginx 1.17.3 php 7.3.8 openssl 1.1.1c nginx docker ...

  7. 持续构建:NodeJS的Alpine镜像

    Alpine镜像目前并不能通过npm add来安装所有的npm和nodejs的版本,所以在easypack的Alping镜像中使用两种方式来进行NodeJS镜像的生成,Alpine中已经打包的直接使用 ...

  8. alpine linux中文乱码,alpine 镜像 java 日志中文问号乱码

    alpine 镜像 java 日志中文问号乱码 0x00 前言 吾使用 alpine 作为基础镜像构建了 jdk8 镜像,为线上业务的 Java 微服务架构提供支持,但是有容器运行的 java 服务中 ...

  9. 在docker镜像中加入环境变量

    原文链接 前言 reference:https://vsupalov.com/docker-build-time-env-values/ 很多时候,我们需要在docker镜像中加入环境变量,本人了解的 ...

最新文章

  1. C++官方自带可持久化平衡树rope的3000行源码
  2. mysql大于等于怎么写_数据库中大于等于0小于等于100怎样表达
  3. codeforces gym-101741 Elevator 动态规划、单调队列
  4. sass 安装和使用
  5. java中strictfp么意思_什么时候应该在java中使用“strictfp”关键字?
  6. Linux内核分析 - 网络[十四]:IP选项
  7. SAP License:ERP学习的一些个人建议
  8. 罗永浩要造智能音箱;苹果承认bug;微软特制AI曝光 | 极客头条
  9. perl DBD Informix install and test
  10. 黑马程序员MySQL-视图SQL笔记
  11. a标签下载pdf文件
  12. 夏普科学计算机标准差,疯狂期货夏普比率公式里面标准差实际应该怎么算
  13. 指付通盗刷信用卡维权连载--9月2日维权纪实
  14. nvidia-smi 在 MIG M. 出现 Disabled
  15. 计算机网络的硬盘组成,网络磁盘
  16. 听dalao讲课8.4
  17. AM4379芯片的GPIO接口点灯LED
  18. date.gettime()与时间的获取
  19. 有哪些值得推荐的 Python 开发工具
  20. python26章_44G-26章节Python盖世修炼最新实战 全新升级版Python全栈架构师高级课程 从零实战...

热门文章

  1. c语言处理rna序列,RNAseq 完整操作流程以及后续例子操作
  2. 朋友圈被公司“无偿征用”,该怎么办?
  3. linux 输出到文件 新,如何将Linux命令输出保存到文件的两种方法
  4. 刚刚,2019年中国信息通信服务交流研讨会盛大召开!
  5. mysqlin会使用索引吗
  6. 模型优化与tensorflow
  7. 笑谈贝叶斯网络(干货)上
  8. Java JNA (三)—— 结构体使用及简单示例
  9. 中型B2C电商行业BI系统推荐?
  10. PDF在线预览插件touchPDF.js:手机端预览