如何使用CDK将Lambda部署至已有S3存储桶?
从Serverless框架迁移CDK:自定义S3桶部署Lambda代码的正确方式
你当前代码的核心问题
- 路径不匹配:
BucketDeployment上传的代码包文件名是CDK自动生成的带哈希值格式(如asset.abc123.zip),但Lambda配置里硬写了serverless/hello.zip,实际部署时会找不到文件。 - 缺失依赖关系:CDK默认不会保证代码上传完成后再创建Lambda,可能出现Lambda先部署但S3中还没有代码包的情况。
- 手动指定文件名不可靠:硬写
hello.zip会跳过CDK的资产版本控制机制,代码更新后可能因缓存问题无法触发Lambda版本更新。
CDK的自动上传机制及推荐实现
CDK没有像Serverless那样直接指定桶名一键上传的简化配置,但可以通过Asset类实现自动打包、上传到自定义桶,同时保留版本控制能力,是更符合CDK风格的实现方式:
推荐实现代码
import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import * as dotenv from "dotenv"; import * as lambda from "aws-cdk-lib/aws-lambda"; import * as sqs from "aws-cdk-lib/aws-sqs"; import * as s3 from "aws-cdk-lib/aws-s3"; import * as lambdaEventSources from "aws-cdk-lib/aws-lambda-event-sources"; import { Asset } from "aws-cdk-lib/aws-s3-assets"; import { convertDayOfWeekToCron } from "../utils/convertDay"; // 环境配置逻辑(保留原有逻辑) const environment = process.env.NODE_ENV || "dev"; dotenv.config({ path: `.env.${environment}` }); export class AwsCdkEventsStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // 导入已有的自定义S3桶 const lambdaBucket = s3.Bucket.fromBucketName( this, "LambdaBucket", process.env.S3_BUCKET || "", ); // 创建S3 Asset:自动打包lambda目录并上传到自定义桶 const lambdaCodeAsset = new Asset(this, "LambdaCodeAsset", { path: "./lambda", bucket: lambdaBucket, keyPrefix: "scheduler-service", exclude: ["**/*.ts"], }); // 定义Lambda函数,引用自定义桶中的Asset代码 const helloWorldFunction = new lambda.Function(this, "HelloWorldFunction", { runtime: lambda.Runtime.NODEJS_20_X, // 直接使用Asset生成的S3对象键,无需手动指定文件名 code: lambda.Code.fromBucket(lambdaBucket, lambdaCodeAsset.s3ObjectKey), handler: "hello.handler", environment: { STAGE: process.env.NODE_ENV || "dev", }, }); // SQS事件源配置(保留原有逻辑) const queueArn: string = process.env.SQS_ARN || ""; const queue = sqs.Queue.fromQueueArn(this, "ImportQueue", queueArn); queue.grantConsumeMessages(helloWorldFunction); helloWorldFunction.addEventSource( new lambdaEventSources.SqsEventSource(queue), ); } }
关键改进点说明
- 自动打包与版本控制:
Asset类会自动将./lambda目录打包成带哈希值的zip包,代码更新时哈希值变化,会自动触发Lambda版本更新,避免缓存问题。 - 依赖自动处理:CDK会自动识别
lambdaCodeAsset与helloWorldFunction的依赖关系,确保代码先上传到S3,再创建/更新Lambda。 - 简化配置:无需手动配置
BucketDeployment,Asset已整合打包、上传逻辑,更贴合CDK的声明式编程风格。
备选方案:基于BucketDeployment的修正
如果坚持使用BucketDeployment,需要修正路径和依赖关系:
// 保留BucketDeployment配置 const lambdaCodeAsset = new s3Deploy.BucketDeployment( this, "LambdaCodeAssetDeployment", { sources: [s3Deploy.Source.asset("./lambda", { exclude: ["**/*.ts"] })], destinationBucket: lambdaBucket, destinationKeyPrefix: "scheduler-service", }, ); // 创建Lambda时引用正确的文件路径,并添加依赖 const helloWorldFunction = new lambda.Function(this, "HelloWorldFunction", { runtime: lambda.Runtime.NODEJS_20_X, code: lambda.Code.fromBucket(lambdaBucket, lambdaCodeAsset.sourceAsset?.s3ObjectKey || ""), handler: "hello.handler", environment: { STAGE: process.env.NODE_ENV || "dev", }, }); // 强制Lambda等待代码上传完成 helloWorldFunction.node.addDependency(lambdaCodeAsset);
但这种方式不如Asset方案简洁,推荐优先使用Asset实现。
内容的提问来源于stack exchange,提问作者Parthiva
相关产品推荐
相关产品推荐

