如何确保容器内griddb_node针对Node.js v18(ABI108)编译解决ERR_DLOPEN_FAILED
问题背景
开发基于Node.js/Express.js的应用,使用官方griddb_node客户端连接GridDB Cloud,在Docker容器内运行initdb.js脚本时触发ERR_DLOPEN_FAILED错误:griddb_client.node是针对NODE_MODULE_VERSION 64编译的,而容器内Node.js v18对应ABI版本为108。
已尝试操作
- 在
npm install前设置ENV npm_config_build_from_source=true - 在Docker镜像中安装
build-essential、python3、make、g++等构建工具 - 添加
.dockerignore排除宿主机node_modules - 在Dockerfile中执行
npm rebuild griddb_node --build-from-source - 删除宿主机
node_modules并重新构建
但容器内仍存在ABI-64版本的griddb_client.node。
相关配置文件
Dockerfile
FROM node:18-slim WORKDIR /usr/src/app # Copy the pre-downloaded GridDB C Client package into the image COPY debs/griddb-c-client_5.8.0_amd64.deb /tmp/ # Install runtime deps, the GridDB C client, and build tools RUN apt-get update && \ apt-get install -y --no-install-recommends \ libssl3 \ libstdc++6 \ ca-certificates \ wget \ build-essential \ python3 \ make \ g++ && \ dpkg -i /tmp/griddb-c-client_5.8.0_amd64.deb && \ rm -rf /var/lib/apt/lists/* /tmp/griddb-c-client_5.8.0_amd64.deb # Copy package manifests and force rebuild of native modules at install ENV npm_config_build_from_source=true COPY package.json package-lock.json ./ RUN npm install --production # Copy the rest of your application source COPY . . # Expose the application port EXPOSE 3000 # Start the application CMD ["node", "app.js"]
docker-compose.yml
version: '3.8' services: studyive: build: . dns: - 8.8.8.8 - 1.1.1.1 ports: - "3000:3000" env_file: - .env volumes: - ./uploads:/usr/src/app/uploads - ./public:/usr/src/app/public restart: unless-stopped
initdb.js核心代码
// initdb.js const store = require('./config/griddb'); const griddb = require('griddb_node'); async function init() { await Promise.all([ // users容器创建 store.putContainer({ name: 'users', columnInfoList: [ ['id', griddb.Type.STRING], ['username', griddb.Type.STRING], ['passwordHash', griddb.Type.STRING], ['role', griddb.Type.STRING], ], type: griddb.ContainerType.COLLECTION, rowKey: true }), // assignments容器创建 store.putContainer({ name: 'assignments', columnInfoList: [ ['id', griddb.Type.STRING], ['userId', griddb.Type.STRING], ['title', griddb.Type.STRING], ['dueDate', griddb.Type.TIMESTAMP], ['done', griddb.Type.BOOL], ['notes', griddb.Type.STRING] ], type: griddb.ContainerType.COLLECTION, rowKey: true }), // 其他容器创建逻辑... ]); console.log('Containers created.'); process.exit(0); } init().catch(console.error);
错误输出
执行docker-compose build --no-cache构建成功,但运行docker-compose run --rm studyive node initdb.js时报错:
WARN[0000] /mnt/c/Users/unita/StudyIve/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion node:internal/modules/cjs/loader:1460 return process.dlopen(module, path.toNamespacedPath(filename)); ^ Error: The module '/usr/src/app/node_modules/griddb_node/lib/griddb_client.node' was compiled against a different Node.js version using NODE_MODULE_VERSION 64. This version of Node.js requires NODE_MODULE_VERSION 108. Please try re-compiling or re-installing the module (for instance, using `npm rebuild` or `npm install`). at Module._extensions..node (node:internal/modules/cjs/loader:1460:18) at Module.load (node:internal/modules/cjs/loader:1203:32) at Module._load (node:internal/modules/cjs/loader:1019:12) at Module.require (node:internal/modules/cjs/loader:1231:19) at require (node:internal/modules/helpers:177:18) at Object.<anonymous> (/usr/src/app/node_modules/griddb_node/lib/griddb_node.js:1:14) at Module._compile (node:internal/modules/cjs/loader:1364:14) at Module._extensions..js (node:internal/modules/cjs/loader:1422:10) at Module.load (node:internal/modules/cjs/loader:1203:32) at Module._load (node:internal/modules/cjs/loader:1019:12) { code: 'ERR_DLOPEN_FAILED' } Node.js v18.20.8
解决方案
1. 修正Dockerfile构建逻辑
修改Dockerfile中的依赖安装步骤,强制从源码构建并避免锁定预编译包:
# 移除原有的package-lock.json复制和安装步骤,替换为: RUN rm -f package-lock.json ENV npm_config_build_from_source=true COPY package.json ./ RUN npm install --production --build-from-source && \ npm rebuild griddb_node --build-from-source
原因:package-lock.json会锁定预编译二进制包的版本,删除后重新安装会强制基于当前容器的Node.js环境从源码编译griddb_node。
2. 确保griddb_node与C Client版本匹配
在package.json中明确指定griddb_node版本为5.8.0(与已安装的GridDB C Client版本一致):
"dependencies": { "griddb_node": "5.8.0" }
3. 完善.dockerignore配置
确保.dockerignore包含以下内容,防止宿主机文件干扰容器构建:
node_modules/ package-lock.json npm-debug.log
4. 彻底清理缓存后重新构建
执行以下命令构建镜像,确保无缓存干扰:
docker-compose build --no-cache --force-rm
5. 验证编译结果
进入容器验证griddb_node的ABI版本是否匹配:
docker-compose run --rm studyive bash # 查看容器内Node.js的ABI版本 node -p "process.versions.modules" # 应输出108 # 检查griddb_node的安装状态 npm ls griddb_node
关键原因
griddb_node的npm包默认提供的预编译二进制包针对旧版Node.js(NODE_MODULE_VERSION 64对应Node.js 10.x),而Node.js 18对应ABI 108,必须强制在容器内基于当前Node.js环境从源码编译,同时确保GridDB C Client依赖已正确安装。
内容的提问来源于stack exchange,提问作者Sadaf Farooqi

