本文共 4545 字,大约阅读时间需要 15 分钟。
在Jenkins的镜像中集成NodeJS插件,发现node和npm都无法执行,最终确认之后定位为libc的问题,在这篇文章中进行memo。中介来说,这个问题还可以描述为:如何在Alpine镜像中支持NodeJS,或者如何在Alpine镜像中使用npm和node。
现象描述
安装了NodeJS插件之后,创建了一个FreeStyle的Job来确认NPM的正常动作
结果却发现,npm和node获取版本的命令都无法正常动作。Started by user rootRunning as SYSTEMBuilding in workspace /data/jenkins/workspace/nodejs-freestyle-job[nodejs-freestyle-job] $ /bin/sh -xe /tmp/jenkins8839673353818507589.sh+ npm -venv: ‘node’: No such file or directoryBuild step 'Execute shell' marked build as failureFinished: FAILURE
原因分析
NodeJS插件也是将NodeJS的安装包下载到本地,然后设定PATH所起的作用。经确认,已经成功下载,并且解压后的包的整个大小也使用du命令进行了确认,和官网下载解压下来大小一致。
/data/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-8.6.0 # lsCHANGELOG.md LICENSE README.md bin include lib share/data/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-8.6.0 # ls binnode npm npx/data/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-8.6.0 #
现象是node和npm存在但是运行时提示错误,node较为简单,因为它是一个二进制文件,我们可以通过分析其动态链接库的组成来进行初步的问题确认。
/data/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-8.6.0 # ldd bin/node /lib64/ld-linux-x86-64.so.2 (0x7efd24f50000) libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7efd24f50000) librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7efd24f50000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x7efd24dfb000) libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7efd24f50000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7efd24de7000) libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7efd24f50000) libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7efd24f50000)Error relocating bin/node: __isinf: symbol not foundError relocating bin/node: __register_atfork: symbol not foundError relocating bin/node: __isnan: symbol not foundError relocating bin/node: backtrace: symbol not found/data/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-8.6.0 #
而正确的则应该是这样的链接库
[root@liumiaocn bin]# ldd node linux-vdso.so.1 => (0x00007ffd7b0fe000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f94f0d08000) librt.so.1 => /lib64/librt.so.1 (0x00007f94f0b00000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f94f07f8000) libm.so.6 => /lib64/libm.so.6 (0x00007f94f04f6000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f94f02e0000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f94f00c3000) libc.so.6 => /lib64/libc.so.6 (0x00007f94efcf5000) /lib64/ld-linux-x86-64.so.2 (0x0000563624981000)[root@liumiaocn bin]#
基本可以断定这是Alpine镜像特有的问题,因为其使用的非libc而是musl。以下记录一下常见的解决方法。
对应方法1: 换掉Alpine镜像
使用glibc为基础的镜像比如CentOS,常见发行版的Linux基本都没有这个问题,即可解决这个问题,但是Alpine镜像非常小的这个利点也随之而去。
对应方法2: 添加相关的依赖
理论上来说,添加ldd提示的所缺少的动态链接库中缺少的内容,应该能够解决这个问题。基于musl的Alpine中安装glibc是一个很奇怪的想法,但是github上确实存在这样一种解决方案。之前使用这种方式成功地解决了Oracle发行版的JDK的Alpine镜像的类似问题。但是单纯安装响应的glibc的包到Alpine镜像中,显然没有能够直接解决这个问题,memo信息如下:
步骤1: 下载key
执行命令:
apk --no-cache add ca-certificates wget wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
执行日志如下所示
~ # apk --no-cache add ca-certificates wgetfetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gzfetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz(1/1) Installing wget (1.20.3-r0)Executing busybox-1.29.3-r10.triggerOK: 350 MiB in 112 packages~ # 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.30-r0/glibc-2.30-r0.apk
步骤3: 安装
执行命令:apk add glibc-2.30-r0.apk
执行日志如下所示:
~ # lsglibc-2.30-r0.apk~ # apk add glibc-2.30-r0.apk fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz(1/1) Installing glibc (2.30-r0)OK: 359 MiB in 113 packages~ #
结果问题仍然存在。另外重新安装了了libstdc++和libgcc仍然没有解决这个问题。不存在的情况下,动态链接库会有如下错误提示:
Error loading shared library libstdc++.so.6: No such file or directory (needed by node)Error loading shared library libgcc_s.so.1: No such file or directory (needed by node)
虽然此路暂未走通,但是应该存在这样一种方式解决。
对应方法3: 使用基于libc版本的NodeJS发行版(源码生成方式)
从NodeJS插件使用中可以看到,如果设定的是从nodejs.org获取安装的情况下,使用的时候会发现诸如下列的执行日志信息:
Unpacking https://nodejs.org/dist/v8.6.0/node-v8.6.0-linux-x64.tar.gz to /data/jenkins/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs-8.6.0 on Jenkins
从中可以清楚的看到,此NodeJS插件是从官方下载了相应的压缩包,然后展开,仅此而已。
而目前的官方的NodeJS所提供的下载,并没有直接有Alpine Linux可以直接使用的二进制文件,所以可以使用Alpine容器中手动从源码生成的方式,然后将生成的二进制内容拷贝到JENKINS_HOME 下的tools下的响应路径的NodeJS予以替换即可。对应方法4: 使用Alpine的nodejs包
Alpine的nodejs包,使用apk add nodejs即可。使用方式可以参看如下内容:
- https://liumiaocn.blog.csdn.net/article/details/102595065
但是限制在于版本的支持是特定的,如有特定版本的需求仍然需要从源码编译的方式进行解决。
转载地址:https://liumiaocn.blog.csdn.net/article/details/102587460 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!