如何实现创建并复制加密AMI的正确流程以避免Lambda超时?
Lambda实现EC2 AMI备份加密的正确流程
你的问题核心是单个Lambda同步等待AMI创建完成导致超时——Lambda最长仅支持15分钟超时,而AMI创建(尤其是大实例)往往会超过这个时间。正确的做法是把任务拆成异步触发+事件驱动的多阶段流程,避免长时间阻塞。
具体实现步骤
1. 拆分任务为两个独立Lambda
把原函数拆成两个职责单一的Lambda,通过事件触发衔接:
- Lambda 1:初始化AMI创建:仅负责触发EC2创建AMI,记录关键信息到DynamoDB后立即结束,不等待AMI完成。
- Lambda 2:处理加密复制:当AMI状态变为
available时,自动触发该Lambda执行加密复制操作。
2. 用DynamoDB追踪AMI状态
创建一个DynamoDB表(比如ami-backup-tracker),主键设为ami_id(字符串类型),用于记录每个AMI的实例ID、所属区域、创建时间、状态等信息,确保后续能准确识别我们需要处理的AMI。
3. 配置EventBridge监听AMI状态变化
通过EventBridge监听EC2的EC2 Image State-change Notification事件,当AMI状态变为available时,自动触发第二个Lambda。
代码实现
Lambda 1:初始化AMI创建
import boto3 import os from datetime import datetime def lambda_handler(event, context): ec2 = boto3.client('ec2') dynamodb = boto3.resource('dynamodb') tracker_table = dynamodb.Table(os.environ['AMI_TRACKER_TABLE']) instance_ids = os.environ['INSTANCE_IDS'].split(",") current_region = context.invoked_function_arn.split(":")[3] for instance_id in instance_ids: ami_name = f"Backup-{instance_id}-{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}" # 触发AMI创建,立即返回,不等待 create_response = ec2.create_image( InstanceId=instance_id, Name=ami_name, NoReboot=True ) new_ami_id = create_response['ImageId'] # 把AMI信息写入DynamoDB追踪 tracker_table.put_item( Item={ 'ami_id': new_ami_id, 'instance_id': instance_id, 'region': current_region, 'status': 'pending', 'created_at': datetime.now().isoformat() } ) print(f"已触发实例 {instance_id} 的AMI创建,ID:{new_ami_id}") return {"status": "所有AMI创建任务已触发"}
Lambda 2:加密复制可用的AMI
import boto3 import os from datetime import datetime def lambda_handler(event, context): ec2 = boto3.client('ec2') dynamodb = boto3.resource('dynamodb') tracker_table = dynamodb.Table(os.environ['AMI_TRACKER_TABLE']) # 从EventBridge事件中提取AMI信息 event_detail = event['detail'] target_ami_id = event_detail['image-id'] source_instance_id = event_detail['source-instance-id'] current_region = context.invoked_function_arn.split(":")[3] # 仅处理状态为available的AMI if event_detail['state'] != 'available': return {"status": f"AMI {target_ami_id} 状态不是available,跳过处理"} # 验证该AMI是我们追踪的任务 tracker_response = tracker_table.get_item(Key={'ami_id': target_ami_id}) if 'Item' not in tracker_response: return {"status": f"AMI {target_ami_id} 不在追踪列表中,跳过处理"} # 执行加密复制 encrypted_ami_name = f"Encrypted-Backup-{source_instance_id}-{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}" copy_response = ec2.copy_image( SourceImageId=target_ami_id, SourceRegion=current_region, Name=encrypted_ami_name, Encrypted=True ) encrypted_ami_id = copy_response['ImageId'] # 更新DynamoDB中的状态 tracker_table.update_item( Key={'ami_id': target_ami_id}, UpdateExpression="set status = :new_status, encrypted_ami_id = :enc_id", ExpressionAttributeValues={ ':new_status': 'encrypted', ':enc_id': encrypted_ami_id } ) print(f"已完成AMI {target_ami_id} 的加密复制,新AMI ID:{encrypted_ami_id}") # 可选:添加旧AMI清理逻辑,比如删除7天前的非加密AMI # 这里可以根据保留策略实现 return {"status": f"加密AMI {encrypted_ami_id} 创建成功"}
EventBridge规则配置
- 创建新规则,选择事件模式
- 事件源选择
AWS EC2,事件类型选择EC2 Image State-change Notification - 事件模式JSON如下:
{ "source": ["aws.ec2"], "detail-type": ["EC2 Image State-change Notification"], "detail": { "state": ["available"] } }
- 目标选择第二个Lambda函数,完成配置。
权限注意事项
- Lambda 1需要权限:
ec2:CreateImage、dynamodb:PutItem - Lambda 2需要权限:
ec2:CopyImage、dynamodb:GetItem、dynamodb:UpdateItem - EventBridge需要权限触发Lambda 2
内容的提问来源于stack exchange,提问作者Max Koretskyi
相关产品推荐
相关产品推荐

