Node.js 的 Docker 有基于 Alpine 的版本。在这个 Docker 中使用 7zip-bin 库的时候遇到了错误,无法正常启动。
一个简单的重现 Dockerfile
可以这么写:
FROM node:10-alpine
RUN mkdir -p example && \
cd example && \
yarn init -y && \
yarn add 7zip-bin && \
mkdir /lib64 && \
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
ADD run.sh /run.sh
RUN chmod +x /run.sh
CMD ["/run.sh"]
其中,run.sh
可以写:
cd example
$(node -e "console.log(require('7zip-bin').path7za)")
报错的内容是:
/run.sh: line 2: /example/node_modules/7zip-bin/linux/x64/7za: not found
通过进入 Docker 内部观察不难发现,/example/node_modules/7zip-bin/linux/x64/7za
这个文件实际是真实存在的,但是在使用的时候系统却报错 not found
。造成这一问题的原因,可能是动态库缺失。
通过 ldd
命令可以列出动态库依赖关系(文档):
ldd /example/node_modules/7zip-bin/linux/x64/7za
输出结果是:
/lib64/ld-linux-x86-64.so.2 (0x7febe540e000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7febe540e000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x7febe52b9000)
libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7febe540e000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7febe52a5000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7febe540e000)
注意到缺少了 /lib64/ld-linux-x86-64.so.2
这个动态库,因此导致了 7zip-bin
这个库无法正常使用。造成这个的原因是,Alpine 使用的是 musl,而 7zip-bin
使用的二进制文件是基于 glibc 编译出来的。要解决这个问题,有两种思路:
- 在 Alpine 中安装 libc 的兼容库:
RUN apk add --no-cache libc6-compat
; - 或者,
ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2
将 musl 的版本软连过去,直接让7zip-bin
的二进制使用
当然,最佳的方案是不使用 7zip-bin
中的 pre-build 版本,而改用 Alpine 的 p7zip 版本。用 Alpine 的包管理器安装好 pz7ip
之后(apk add p7zip
),使用类似下面的代码直接替换脚本就好了:
cp $(type -p 7za) $(node -p "require('7zip-bin').path7za")