基于AWS CDK将Lambda迁移至ECS/EKS及差异咨询
Lambda冷启动迁移至ECS/EKS的CDK最小改动方案及核心差异
一、Lambda与ECS/EKS核心差异
- 执行模型:Lambda是事件驱动的无服务器函数,按需启动执行,完成后销毁;ECS/EKS是容器集群,容器实例长期运行或按需缩放,支持持续服务和一次性任务。
- 冷启动表现:Lambda存在冷启动(初始化运行时、加载代码/层),首次请求或闲置后重启会有延迟;ECS/EKS容器启动后持续运行,无冷启动延迟(新实例启动除外,可通过预缩放规避)。
- 资源控制:Lambda资源(内存、CPU)绑定,配置选项有限;ECS/EKS可自定义容器CPU、内存、存储等资源,支持GPU等特殊硬件。
- 部署方式:Lambda支持代码包、Docker镜像两种部署;ECS/EKS仅支持容器镜像,需管理集群、任务定义、服务等组件。
- 事件触发:Lambda原生集成AWS全品类事件源(API Gateway、SQS、EventBridge等);ECS/EKS需借助中间组件(如EventBridge触发任务、API Gateway通过VpcLink对接服务)实现事件驱动。
- 成本模型:Lambda按请求数+执行时间付费;ECS/EKS按实例/资源使用时长付费,Fargate模式按任务运行时长付费。
二、CDK最小代码改动迁移方案
由于现有代码已使用DockerImageFunction,可复用Docker镜像实现最小改动迁移,优先选择ECS Fargate(无服务器容器,无需管理EC2实例)。
1. 添加ECS依赖
在CDK代码顶部导入ECS相关模块:
import * as ecs from 'aws-cdk-lib/aws-ecs'; import * as targets from 'aws-cdk-lib/aws-events-targets'; import * as apigateway from 'aws-cdk-lib/aws-apigateway';
2. 复用Docker镜像创建ECS任务与服务
以amaServiceLambda为例,替换Lambda创建逻辑为ECS Fargate服务:
// 在AmaStack类中添加ECS服务属性 public readonly amaServiceEcsService: ecs.FargateService; // 在constructor中创建ECS集群、任务定义与服务 const ecsCluster = new ecs.Cluster(this, `AmaEcsCluster-${props.stage}`, { vpc: props.vpcStack.vpc, clusterName: `AmaEcsCluster-${props.stage}`, }); // 复用Lambda的IAM托管策略 const managedPolicies = [ ManagedPolicy.fromAwsManagedPolicyName('AWSLambdaExecute'), ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLambdaInsightsExecutionRolePolicy'), ManagedPolicy.fromAwsManagedPolicyName('AmazonBedrockFullAccess'), ManagedPolicy.fromAwsManagedPolicyName('AmazonS3FullAccess'), ]; // 创建ECS任务角色(复用Lambda权限) const amaTaskRole = new Role(this, `AmaServiceTaskRole-${props.stage}`, { roleName: `AmaServiceTaskRole-${props.stage}`, assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), managedPolicies: managedPolicies, }); // 创建Fargate任务定义 const amaTaskDefinition = new ecs.FargateTaskDefinition(this, `AmaServiceTaskDef-${props.stage}`, { memoryLimitMiB: 2048, // 对应Lambda的内存配置 cpu: 1024, taskRole: amaTaskRole, executionRole: amaTaskRole, // 复用同一角色简化配置 }); // 添加容器,复用Lambda使用的Docker镜像 amaTaskDefinition.addContainer(`AmaServiceContainer-${props.stage}`, { image: ecs.ContainerImage.fromAsset('path/to/your/docker/context'), // 或使用ECR镜像ARN environment: { // 完全复用Lambda的环境变量 BUCKET_PREFIX: AMA.BUCKET_PREFIX, MODEL: AMA.MODEL, EMBEDDING: AMA.EMBEDDING, LANGCHAIN_TRACING_V2: 'true', LANGCHAIN_ENDPOINT: props.langchainEndpoint, LANGCHAIN_API_KEY: props.langchainApiKey, LANGCHAIN_PROJECT: `AMA-${props.stage}`, STAGE_NAME: props.stage, BUCKET_PREFIX: getCommonBucketName(props.accountId, props.stage), LLM_TOP_P: '0.2', OPENAI_API_KEY: openAIKey.unsafeUnwrap(), LLM_TEMPERATURE: '0.2', RETRIEVER_K: '3', ...commonEnvironmentVariables, }, logging: ecs.LogDriver.awsLogs({ streamPrefix: `AmaService-${props.stage}` }), portMappings: [{ containerPort: 8080 }], // 容器暴露端口,用于API Gateway对接 }); // 创建Fargate服务 this.amaServiceEcsService = new ecs.FargateService(this, `AmaServiceEcsService-${props.stage}`, { cluster: ecsCluster, taskDefinition: amaTaskDefinition, desiredCount: 1, assignPublicIp: false, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, }); // 授权容器访问Secret(复用Lambda的授权逻辑) openAISecret.grantRead(amaTaskRole);
3. 修改API Gateway集成
将LambdaIntegration替换为ECS服务集成,通过VpcLink对接私有子网中的ECS服务:
// 创建VpcLink对接ECS服务 const vpcLink = new apigateway.VpcLink(this, `AmaServiceVpcLink-${props.stage}`, { targets: [this.amaServiceEcsService], }); // 替换原有Lambda集成 this.configureMethodOnResource(AMAFeedbackResource, Methods.POST, new apigateway.HttpIntegration( `http://${this.amaServiceEcsService.loadBalancer.loadBalancerDnsName}/feedback`, { vpcLink: vpcLink } ));
注:若使用ALB模式的ECS服务(ecsPatterns.ApplicationLoadBalancedFargateService),可直接用ALB域名作为集成地址。
4. 迁移定时触发的Lambda(如embeddingPollingLambda)
用EventBridge直接触发ECS一次性任务,替代Lambda:
// 创建定时任务的ECS任务定义 const embeddingPollingTaskDef = new ecs.FargateTaskDefinition(this, `EmbeddingPollingTaskDef-${props.stage}`, { memoryLimitMiB: 1024, cpu: 512, taskRole: new Role(this, `EmbeddingPollingTaskRole-${props.stage}`, { roleName: `EmbeddingPollingTaskRole-${props.stage}`, assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), managedPolicies: managedPolicies, }), }); embeddingPollingTaskDef.addContainer(`EmbeddingPollingContainer-${props.stage}`, { image: ecs.ContainerImage.fromAsset('path/to/your/docker/context'), environment: { ...commonEnvironmentVariables, EMBEDDING_LOG_QUEUE: this.embeddingLogQueue.queueUrl, }, logging: ecs.LogDriver.awsLogs({ streamPrefix: `EmbeddingPolling-${props.stage}` }), }); // 修改EventBridge规则目标为ECS任务 const rule = new Rule(this, `EventBridge-${EventBridgeRules.AMA_LOG_POLLING}`, { description: `Rule to trigger embedding polling task every ${EMBEDDING_LOG_POLLING_INTERVAL} minutes`, schedule: Schedule.rate(EMBEDDING_LOG_POLLING_INTERVAL), }); if (ACTIVE_EMBEDDING_LOG_STACKS.find(stack => stack.accountId === props.accountId && stack.stageName === props.stage)) { rule.addTarget(new targets.EcsTask({ cluster: ecsCluster, taskDefinition: embeddingPollingTaskDef, taskCount: 1, subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, })); }
5. 最小改动关键策略
- 复用Docker镜像:直接使用Lambda的Docker镜像,无需修改业务代码(一次性任务无需改为Web服务)。
- 复用权限与环境变量:复制Lambda的IAM策略、环境变量到ECS任务,避免重新配置权限。
- 逐步迁移:优先迁移冷启动严重的核心Lambda,其余Lambda保留,逐步替换,降低风险。
内容的提问来源于stack exchange,提问作者Aryan Raj
相关产品推荐
相关产品推荐

