Lambda函数运行EventBridge Atlas报EROFS只读文件系统错误
问题背景
- 需求为在Lambda函数内通过eventbridge-atlas生成AsyncAPI文档后上传至S3存储桶,本地调试时所有功能运行正常:文件默认存储在
/tmp目录(Lambda环境自带该可写目录),已在eventbridge-atlas代码中新增逻辑,用于处理/tmp目录下生成文件的上传S3流程。 - Lambda函数执行时最初运行的命令如下:
npx @asyncapi/generator /tmp/events.yml @asyncapi/html-template -o /tmp --force-write
- 按预期该命令应将生成的文档写入Lambda的
/tmp目录,本地运行时逻辑完全正常,但实际执行抛出如下错误:
2022-06-28T17:46:49.457Z 90c863cb-b7de-4906-a71c-6aad84fd8bd4 INFO e Error: Command failed: npx @asyncapi/generator /tmp/events.yml @asyncapi/html-template -o /tmp --force-write Error: EROFS: read-only file system, mkdir '/home/sbx_user1051' command not found: generator at ChildProcess.exithandler (child_process.js:383:12) at ChildProcess.emit (events.js:400:28) at ChildProcess.emit (domain.js:475:12) at maybeClose (internal/child_process.js:1088:16) at Process.ChildProcess._handle.onexit (internal/child_process.js:296:5) { killed: false, code: 1, signal: null, cmd: 'npx @asyncapi/generator /tmp/events.yml @asyncapi/html-template -o /tmp --force-write', stdout: '', stderr: "Error: EROFS: read-only file system, mkdir '/home/sbx_user1051'\n" + 'command not found: generator\n' }
- 初步排查确认:相关逻辑除了写入指定的
/tmp目录外,还会尝试在/home/sbx_user1051路径下创建目录,而Lambda环境除/tmp外的文件系统均为只读,因此触发报错。 - 后续调整方案:修改eventbridge-atlas代码,不再执行bash命令,改为直接引入对应Node模块调用,仍然出现相同错误,完整错误栈如下:
{ "errorType": "Runtime.UnhandledPromiseRejection", "errorMessage": "Error: EROFS: read-only file system, mkdir '/home/sbx_user1051'", "reason": { "errorType": "Error", "errorMessage": "EROFS: read-only file system, mkdir '/home/sbx_user1051'", "code": "EROFS", "errno": -30, "syscall": "mkdir", "path": "/home/sbx_user1051", "stack": [ "Error: EROFS: read-only file system, mkdir '/home/sbx_user1051'" ] }, "promise": {}, "stack": [ "Runtime.UnhandledPromiseRejection: Error: EROFS: read-only file system, mkdir '/home/sbx_user1051'", " at process.<anonymous> (/var/runtime/index.js:35:15)", " at process.emit (events.js:400:28)", " at process.emit (domain.js:475:12)", " at process.emit (/var/task/node_modules/@asyncapi/generator/node_modules/source-map-support/source-map-support.js:516:21)", " at processPromiseRejections (internal/process/promises.js:245:33)", " at processTicksAndRejections (internal/process/task_queues.js:96:32)" ] }
- 核心诉求:寻找可行的解决方案,确认是否有开发者成功在Lambda函数中部署eventbridge-atlas实现文档自动生成。
解决方案
报错根因是@asyncapi/generator运行时默认读取当前用户主目录路径,尝试在主目录下创建缓存、临时配置目录,Lambda运行时的用户主目录恰好是只读的/home/sbx_user1051,和你指定的输出路径没有关系。
两个可直接落地的方案:
- 配置环境变量重定向所有可写路径到/tmp
在Lambda函数配置中添加以下环境变量,把所有默认写入用户目录的路径全部指向可写的/tmp下:HOME=/tmpNPM_CONFIG_CACHE=/tmp/.npmXDG_CONFIG_HOME=/tmp/.configXDG_CACHE_HOME=/tmp/.cache
配置完成后,无论是CLI调用还是直接引入Node模块调用,generator都会把缓存、临时文件全部写到/tmp下,不会再访问只读的/home路径。如果Lambda内存配置较小,注意预留/tmp的存储空间,目前Lambda的/tmp目录最大可配置到10G,常规文档生成场景给512M空间完全够用。
- 如果方案1仍有少量路径写入报错,提前在Lambda初始化阶段创建软链接
在函数冷启动的初始化逻辑中加入如下代码,提前把只读的home路径软链到/tmp下:
该方案相当于给要写入的只读路径做透明转发,所有写入const fs = require('fs'); const { execSync } = require('child_process'); // 冷启动时执行一次即可 if (!fs.existsSync('/tmp/home')) { execSync('mkdir -p /tmp/home/sbx_user1051'); execSync('ln -s /tmp/home/sbx_user1051 /home/sbx_user1051'); }/home/sbx_user1051的操作实际都会落到/tmp下,完全兼容所有依赖的路径写入逻辑,不需要修改第三方包源码。
额外注意事项:
- 不要在Lambda里用npx临时安装依赖,npx会优先将包装到用户目录下,本身就会触发只读问题,直接把
@asyncapi/generator、对应模板、eventbridge-atlas的依赖全部安装到项目node_modules中,和业务代码一起打包上传,冷启动速度也更快。 - 生成完文档上传S3之后,可以主动清理/tmp下生成的临时文件,避免多次调用后/tmp空间占满触发异常。
目前已有不少开发者通过方案1在Lambda上跑通AsyncAPI生成逻辑,不需要修改eventbridge-atlas或者generator的源码,配置完环境变量即可正常运行。
内容的提问来源于stack exchange,提问作者tomvonheill
相关产品推荐
相关产品推荐

