部署Lambda时将Chrome二进制文件复制到/tmp目录的方法
1. Serverless配置的直接错误
你当前的Serverless配置缺少Resources层级,正确的CloudFormation自定义资源配置需要嵌套在resources.Resources下,否则Serverless框架不会识别这个自定义资源。修正后的配置如下:
resources: Resources: CopyChromeBinaries: Type: Custom::CopyChromeBinaries Properties: ServiceToken: arn:aws:lambda:region:ACCOUNT_ID:function:CopyChromeBinaries
2. 核心思路误区:部署阶段无法写入Lambda的/tmp目录
需要明确:Lambda的/tmp目录是实例级临时存储,只有当Lambda实例启动后才会存在,部署阶段(CloudFormation运行自定义资源时)没有活跃的Lambda实例,因此辅助Lambda无法在部署阶段将Chrome二进制文件写入主Lambda的/tmp。你的这个思路从根本上不可行。
3. 可行的替代方案
方案一:Lambda初始化阶段从S3下载二进制文件
将Chrome二进制文件打包后上传到S3桶,在主Lambda的初始化代码段(而非请求处理函数内)添加从S3下载并解压到/tmp的逻辑。每个Lambda实例只会执行一次初始化操作,后续请求复用已解压的二进制文件,避免重复开销:
// 主Lambda初始化代码(在exports.handler之外) const AWS = require('aws-sdk'); const s3 = new AWS.S3(); const fs = require('fs'); const unzip = require('unzipper'); async function initChrome() { const bucketName = 'your-chrome-bucket'; const key = 'chrome-headless.zip'; const tmpPath = '/tmp/chrome'; // 检查/tmp是否已存在Chrome,避免重复下载 if (!fs.existsSync(tmpPath)) { const response = await s3.getObject({ Bucket: bucketName, Key: key }).promise(); await fs.createWriteStream('/tmp/chrome.zip').write(response.Body); await fs.createReadStream('/tmp/chrome.zip').pipe(unzip.Extract({ path: tmpPath })).promise(); // 设置执行权限 fs.chmodSync(`${tmpPath}/chrome`, 0o755); } } // 执行初始化 initChrome().catch(err => console.error('Chrome初始化失败:', err)); exports.handler = async (event) => { // 业务逻辑,此时Chrome已在/tmp目录 const chromePath = '/tmp/chrome/chrome'; // ... 运行无头Chrome的代码 };
同时需要给主Lambda添加S3读取权限,在Serverless配置中添加:
provider: iamRoleStatements: - Effect: Allow Action: - s3:GetObject Resource: arn:aws:s3:::your-chrome-bucket/chrome-headless.zip
方案二:使用Lambda层(若二进制压缩后符合大小限制)
如果Chrome二进制文件的压缩包大小不超过50MB(Lambda层压缩包上限),可以将其打包为Lambda层,部署时附加到主Lambda。层会被自动解压到/opt目录,无需手动处理:
- 将Chrome二进制文件放入层包的
bin目录(或直接根目录),打包为zip - 在Serverless配置中引用该层:
functions: mainLambda: handler: handler.main layers: - arn:aws:lambda:region:ACCOUNT_ID:layer:ChromeHeadless:1
注意:Lambda层的未压缩大小不能超过250MB,且主Lambda代码包+所有层的未压缩总大小不能超过250MB,若Chrome未压缩后接近或超过这个值,此方案不适用。
4. 辅助Lambda的正确使用场景(可选)
如果你希望在部署阶段完成二进制文件的预处理(比如上传到S3),可以用自定义资源辅助Lambda来自动化这个步骤,但无法直接写入Lambda实例的/tmp。比如在部署时将本地的Chrome二进制包上传到S3,避免手动操作:
resources: Resources: UploadChromeToS3: Type: Custom::UploadChromeToS3 Properties: ServiceToken: arn:aws:lambda:region:ACCOUNT_ID:function:UploadChromeToS3 BucketName: your-chrome-bucket LocalFilePath: ./chrome-headless.zip
此时辅助Lambda需要具备S3上传权限,且能读取部署时传递的参数完成上传操作。
内容的提问来源于stack exchange,提问作者planet_hunter

