如何动态更新Launch Template中的AMI ID实现全流程自动化
基于DLM备份AMI自动更新EC2 Auto Scaling组Launch Template的实现方案
整套流程用EventBridge加Lambda做事件驱动即可,不需要人工介入,核心是DLM生成新备份AMI后自动同步到Launch Template(以下简称LT)的默认版本,ASG后续扩容、实例刷新都会自动拉取最新镜像。
前置配置
先在你现有的DLM备份策略里加固定标签,比如给所有生成的AMI打上Source:DLM-AutoBackup、Env:Production的标签,方便后续程序过滤识别,避免拿错其他业务线或环境的镜像。
具体实现步骤
- 配置EventBridge事件规则
事件源选择AWS官方事件源aws.dlm,匹配事件类型为DLM AMI Creation Policy Completed,加过滤条件只匹配你当前按X小时执行备份的DLM策略ID,避免其他备份策略的事件误触发流程。规则的目标直接绑定后续创建的Lambda函数。 - 配置Lambda执行权限
给Lambda绑定最小必要权限即可,不要给全量管理员权限,核心允许的操作如下:[ "ec2:DescribeImages", "ec2:CreateLaunchTemplateVersion", "ec2:ModifyLaunchTemplate", "ec2:DescribeLaunchTemplateVersions", "autoscaling:DescribeAutoScalingGroups", "autoscaling:StartInstanceRefresh" ] - 编写Lambda处理逻辑
逻辑尽量简单,减少故障点,核心流程:- 收到事件后先校验事件携带的DLM策略ID是否为目标备份策略,非目标策略直接退出
- 调用EC2接口查询带之前配置的固定标签、状态为
available的所有AMI,按创建时间倒序排序,取时间最新的AMI ID - 拉取当前LT默认版本的全量配置,仅替换其中的ImageId字段为新拿到的AMI ID,其余配置(实例规格、安全组、密钥对、用户数据、块存储映射等)全部继承旧版本
- 基于替换后的配置创建LT新版本,再把新版本设置为LT的默认版本
- (可选)调用ASG接口触发滚动实例刷新,按业务容忍度配置最小健康实例比例、实例预热时间,逐步把运行中的旧实例替换成新镜像启动的实例
核心Python(boto3)代码参考:
import boto3 from operator import itemgetter ec2_client = boto3.client('ec2') asg_client = boto3.client('autoscaling') # 提前替换为你自己的资源ID TARGET_DLM_POLICY = "policy-xxxxxxxxxxxx" TARGET_LT_ID = "lt-xxxxxxxxxxxx" TARGET_ASG_NAME = "asg-prod-xxxx" AMI_TAG_FILTER = [ {"Name": "tag:Source", "Values": ["DLM-AutoBackup"]}, {"Name": "tag:Env", "Values": ["Production"]}, {"Name": "state", "Values": ["available"]} ] def lambda_handler(event, context): # 校验触发来源合法性 policy_id = event.get("detail", {}).get("policyId") if policy_id != TARGET_DLM_POLICY: return # 获取最新可用备份AMI all_images = ec2_client.describe_images(Filters=AMI_TAG_FILTER)["Images"] if not all_images: raise Exception("No valid backup AMI found") latest_ami = sorted(all_images, key=itemgetter("CreationDate"), reverse=True)[0]["ImageId"] # 获取当前LT默认版本配置 current_lt_default = ec2_client.describe_launch_template_versions( LaunchTemplateId=TARGET_LT_ID, Versions=["$Default"] )["LaunchTemplateVersions"][0] current_version_num = current_lt_default["VersionNumber"] # 创建LT新版本,仅替换AMI new_version = ec2_client.create_launch_template_version( LaunchTemplateId=TARGET_LT_ID, SourceVersion=str(current_version_num), LaunchTemplateData={"ImageId": latest_ami} )["LaunchTemplateVersion"]["VersionNumber"] # 把新版本设为默认 ec2_client.modify_launch_template( LaunchTemplateId=TARGET_LT_ID, DefaultVersion=str(new_version) ) # 可选:触发ASG滚动刷新 asg_client.start_instance_refresh( AutoScalingGroupName=TARGET_ASG_NAME, Strategy="Rolling", Preferences={ "MinHealthyPercentage": 90, "InstanceWarmup": 300, "SkipMatching": True } ) return f"Launch template updated to version {new_version} with AMI {latest_ami}" - 配置异常兜底
- 给Lambda配置死信队列,执行失败时推送消息到SNS告警渠道,方便及时介入
- 逻辑里增加校验:如果新拿到的AMI创建时间早于当前LT默认版本正在使用的AMI,直接终止流程不更新,避免意外回滚到旧镜像
- 实例刷新开启自动回滚,健康检查失败率超过阈值时自动切回旧配置,避免影响业务可用性
避坑提示
- EC2不支持修改Launch Template已经创建完成的版本,所有配置变更必须通过创建新版本实现,不要尝试调用接口修改历史版本
- 如果你的ASG配置了固定LT版本号而非
$Default/$Latest,更新LT默认版本后还要同步修改ASG的LT引用配置,否则新实例不会用新版本配置 - DLM生成的AMI默认会继承源实例的所有标签,直接在DLM策略里配置要追加的固定标签即可,不需要额外打标签的步骤
- Lambda权限严格遵循最小化原则,不要绑定管理员权限策略,避免安全风险
内容的提问来源于stack exchange,提问作者kiroroki
相关产品推荐
相关产品推荐

