Skip to content

[BUG] 无法在docker node:*-alpine 镜像中运行 #44

@wtone

Description

@wtone

只要是 docker node:*-alpine 镜像 就会有问题,在Docker node:18-alpine 镜像容器中,新建一个测试脚本

docker run -it --rm node18:alpine sh
mkdir test
cd test
npm init
npm i imagescript sharp
vi test.js

//test.js

const { arch, platform } = require('os');
console.log(arch(), platform())
try { 
     module.exports = require(`imagescript/codecs/node/bin/${arch()}-${platform()}.node`); 
}catch (err) { throw new Error('unsupported arch/platform: ' + err.message); }

执行就会报错 :Segmentation fault (core dumped)

同样的引用node原生模块,sharp库就不会报错

console.log(platformAndArch())
try {
    module.exports = require(`sharp/build/Release/sharp-${platformAndArch()}.node`);
} catch (err) {
    throw new Error('unsupported arch/platform: ' + err.message);
}

比较后,发现主要是因为platform这个变量取值以及Alpine 的 musl libc 兼容性问题,主要原因是:

1、musl 与 glibc 二进制不兼容

.node 文件是 Node.js 原生模块(C/C++ 编译的二进制文件),若该文件是在 glibc 系统(如 Ubuntu、CentOS)上编译的,而 Alpine 使用 musl libc,两者的二进制接口不兼容,会导致 Node.js 无法正确加载模块(即使文件存在)。

2、获取当前运行环境的平台信息的方式有问题:

// imagescript/codecs/node/index.js

const { arch, platform } = require('os');
module.exports = require(`./bin/${arch()}-${platform()}.node`);

简单通过os.platform获取的值,无法区分linux(Ubuntu、CentOS) 和 linuxmusl(Docker alpine容器),可以参考 sharp库的做法写一个方法来获取platform和arch:

function platformAndArch() {
    const arch = env.npm_config_arch || process.arch;
    const platform = env.npm_config_platform || process.platform;
    const libc = process.env.npm_config_libc ||
        /* istanbul ignore next */
        (detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '');
    const libcId = platform !== 'linux' || libc === detectLibc.GLIBC ? '' : libc;

    const platformId = [];
    if (arch === 'arm') {
        const fallback = process.versions.electron ? '7' : '6';
        platformId.push(`armv${env.npm_config_arm_version || process.config.variables.arm_version || fallback}`);
    } else if (arch === 'arm64') {
        platformId.push(`arm64v${env.npm_config_arm_version || '8'}`);
    } else {
        platformId.push(arch);
    }
    platformId.push(`${platform}${libcId}`);

    return platformId.join('-');
}

在Docker alpine 容器中调用platformAndArch()将得到的platform和arch是 “x64-linuxmusl”

3、本身提供的imagescript/codecs/node/bin/*.node 文件中也没有包含支持x64-linuxmusl.node的文件

需要重新编译一份适配linuxmusl的模块文件(x64-linuxmusl.node),并添加到imagescript/codecs/node/bin/目录下。

Originally posted by @wtone in #30

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions