保障 Amazon Elastic Compute Cloud (Amazon EC2) 的高可用性是运维的核心任务。传统人工值守模式面对突发故障响应滞后,人力成本高。结合 Amazon CloudWatch + Amazon EventBridge + AWS Lambda,可以构建事件驱动的自动化自愈能力,实现 EC2 异常秒级响应,例如状态检查失败自动恢复、流量异常执行网络隔离。
边界说明:CloudWatch 告警自带原生 EC2 自愈动作(Reboot/Stop/Recover),适合简单场景;本文 Lambda 方案适合需要多条件判断、自定义逻辑、联动通知、复杂编排的生产场景。
前置重要提示:
- StatusCheckFailed_System 硬件故障,Reboot 重启无效,必须执行 StopStart 完成宿主机迁移;StatusCheckFailed_Instance 操作系统故障,使用 Reboot。示例脚本必须区分告警指标,否则硬件故障场景自愈失效AWS re:Pos…。
- EventBridge 事件为至少一次投递,未做幂等 / 冷却控制会发生循环反复重启实例,造成业务雪崩;生产务必增加状态判断、最大执行次数限制。
- EC2 状态检查指标默认 1 分钟采集,不需要开启付费详细监控;CPU 等性能指标才需要开启详细监控,避免产生额外 CloudWatch 账单AWS。
- 如果实例属于 Auto Scaling 伸缩组,stop/stopstart 会被 ASG 重新创建实例,自愈逻辑会失效。
- Lambda 如果部署在 VPC 内部,需要 NAT 网关,否则无法调用 EC2 公有 API。
- stopstart 操作会变更实例公网 IP,业务需要绑定 EIP 弹性 IP 防止 IP 变动影响业务访问。
本文面向云系统管理员、DevOps 工程师,完整讲解架构原理、权限配置、代码实现、排障与风险规避。
自动化值守的架构逻辑
- 传统运维 vs 事件驱动自动化 传统运维:告警通知人工,人工登录控制台执行恢复操作,MTTR 恢复时间长。 Lambda 自动化:CloudWatch 指标突破阈值产生告警,告警状态变更经由 EventBridge 投递事件,触发 Lambda 执行 Boto3 脚本,自动完成实例恢复、隔离、打标签,缩短故障恢复时间。
- 组件联动
- 数据源:EC2 输出运行指标、状态检查指标
- 监控层:CloudWatch 采集指标,达到阈值切换 ALARM 告警状态
- 路由层:EventBridge 捕获「CloudWatch Alarm State Change」事件,过滤告警状态,投递到 Lambda
- 执行层:Lambda 接收事件,执行重启、停止、安全组变更、打标签等自愈动作。
表 1:常见 EC2 异常监控指标与处理策略
| 监控指标 (CloudWatch Metric) | 异常场景 | 自动化处理策略 (Lambda Action) |
| StatusCheckFailed_System | 底层硬件、宿主机网络故障 | StopStart(停止再启动,迁移至新物理主机) |
| StatusCheckFailed_Instance | 操作系统内核崩溃、内存耗尽 | Reboot 操作系统重启 |
| CPUUtilization | CPU 持续满载 | 可触发告警通知、打故障标签;谨慎自动重启,避免业务误杀 |
| NetworkIn / NetworkOut | 流量异常疑似攻击 | 修改安全组隔离(高危,建议仅测试环境验证) |
前置条件准备
- 监控说明 EC2 的 StatusCheckFailed 状态检查指标默认即为 1 分钟粒度,无需开启付费详细监控; CPU、磁盘、网络等性能指标如果需要 1 分钟粒度,开启详细监控,会产生 CloudWatch 自定义指标费用。
- IAM 执行角色权限(遵循最小权限原则) 为 Lambda 执行角色配置策略,建议增加资源标签条件,限制仅处理带AutoRepair:true标签的 EC2 实例,防止误操作全部实例。 必需权限:
- 日志:logs:CreateLogGroup、logs:CreateLogStream、logs:PutLogEvents,输出日志到 CloudWatch Logs
- EC2:ec2:DescribeInstances、ec2:RebootInstances、ec2:StopInstances、ec2:StartInstances、ec2:DescribeInstanceStatus
提示:生产环境不要使用全托管粗粒度策略,通过 Tag 条件做权限约束。
- Lambda 基础配置
- 运行时:x
- 超时时间:建议设置 30s,避免 Boto3 调用 AWS API 超时。
- 异步调用配置:配置 DLQ 死信队列 SNS/SQS,处理函数执行失败场景,推送人工告警。
实操步骤:构建异常处理脚本
代码重点:解析告警指标名称,区分 System/Instance 状态检查,做实例运行状态判断,简单防重复执行。
步骤一:编写 Lambda Python 函数
import boto3
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ec2_client = boto3.client(‘ec2’)
def lambda_handler(event, context):
logger.info(f”Receive EventBridge event: {json.dumps(event)}”)
try:
alarm_name = event[‘detail’][‘alarmName’]
alarm_state = event[‘detail’][‘state’][‘value’]
# 仅处理进入ALARM状态事件,忽略OK/INSUFFICIENT_DATA
if alarm_state != “ALARM”:
logger.info(f”当前告警状态 {alarm_state},跳过自愈处理”)
return {“statusCode”:200,”body”:”skip nonalarm state”}
instance_id = extract_instance_id(event)
metric_name = extract_metric_name(event)
if not instance_id:
logger.warning(“事件载荷未解析出InstanceId,直接退出”)
return {“statusCode”:400,”body”:”no instance id found”}
# 查询实例当前状态,避免重复执行自愈
resp = ec2_client.describe_instances(InstanceIds=[instance_id])
instance_state = resp[‘Reservations’][0][‘Instances’][0][‘State’][‘Name’]
if instance_state not in [“running”]:
logger.warning(f”实例 {instance_id} 当前状态 {instance_state},跳过自愈”)
return {“statusCode”:200,”body”:”instance not running, skip”}
# 根据指标选择动作
if metric_name == “StatusCheckFailed_System”:
logger.info(f”[{alarm_name}] System状态检查失败,执行StopStart迁移宿主机 {instance_id}”)
ec2_client.stop_instances(InstanceIds=[instance_id])
elif metric_name == “StatusCheckFailed_Instance”:
logger.info(f”[{alarm_name}] Instance状态检查失败,执行Reboot {instance_id}”)
ec2_client.reboot_instances(InstanceIds=[instance_id])
else:
logger.info(f”指标 {metric_name},仅记录日志,不执行自动恢复”)
return {“statusCode”:200,”body”:f”Processed {instance_id}, metric:{metric_name}”}
except Exception as e:
logger.error(f”自愈处理异常:{str(e)}”,exc_info=True)
raise e
def extract_instance_id(event):
“””从Alarm State Change事件解析InstanceId”””
cfg = event.get(‘detail’,{}).get(‘configuration’,{})
metrics = cfg.get(‘metrics’,[])
for m in metrics:
dims = m.get(‘metricStat’,{}).get(‘metric’,{}).get(‘dimensions’,[])
for d in dims:
if d.get(‘name’) == “InstanceId”:
return d.get(‘value’)
return None
def extract_metric_name(event):
cfg = event.get(‘detail’,{}).get(‘configuration’,{})
metrics = cfg.get(‘metrics’,[])
if metrics:
return metrics[0].get(‘metricStat’,{}).get(‘metric’,{}).get(‘metricName’)
return None
步骤二:创建 CloudWatch 告警
- CloudWatch 控制台进入「每实例指标」
- 针对目标 EC2 实例分别创建两条告警:
- StatusCheckFailed_System:底层硬件故障告警
- StatusCheckFailed_Instance:操作系统状态检查告警
- 阈值设置 >=1,评估周期设置连续 2 个数据点,规避瞬时抖动误报。
步骤三:配置 EventBridge 规则触发 Lambda
- EventBridge 控制台创建规则,事件模式选择CloudWatch Alarm State Change
- 增加过滤条件:状态仅匹配ALARM,过滤 OK、数据不足事件,减少无效调用。
- 目标类型选择 Lambda 函数,选择上面创建的自愈函数。
- 保存规则。
步骤四:部署完成后验证测试
- 给测试 EC2 打上AutoRepair:true标签;
- 可手动将告警强制设置为 ALARM 状态,观察 CloudWatch Logs 日志,确认 Lambda 被触发,动作按预期执行。
生产环境风险与最佳实践汇总
- 幂等与防循环重启EventBridge 为至少一次投递,同一个告警事件可能多次触发;建议增加 DynamoDB 记录实例最近自愈时间,设置冷却窗口(例如 15 分钟内不重复执行自愈),防止无限重启。
- Auto Scaling 组注意伸缩组内实例,不要使用 stop/stopstart 自愈,ASG 会直接终止重建实例;优先使用 ASG 本身健康检查替换故障实例。
- 高危动作管控流量异常自动修改安全组隔离属于高危操作,正式上线前充分测试,一旦逻辑错误会直接锁死业务实例。
- 备份兜底告警Lambda 配置 DLQ 死信队列,自愈脚本执行失败时,通过 SNS 发送邮件 / 短信通知人工介入,不能完全依赖自动化。
- stopstart 会改变公网 IP,业务实例务必绑定 EIP 弹性 IP。
常见排障对照表
| 现象 | 根因 | 解决方向 |
| Lambda 被触发,但是拿不到 InstanceId | EventBridge 事件解析路径不匹配告警类型 | 使用示例中的解析函数;优先测试验证告警事件载荷 |
| StatusCheckFailed_System 告警触发,重启不能恢复业务 | 使用 Reboot 而不是 StopStart,不会迁移宿主机 | System 故障必须 stop_instances,等待停机后 start_instances |
| 实例反复不停重启 | 缺少冷却 / 幂等控制,持续 ALARM 状态反复触发 Lambda | 增加自愈冷却窗口,DynamoDB 记录最近自愈时间 |
| Lambda 执行报 EC2 API 访问拒绝 | IAM 权限缺失,没有 ec2:DescribeInstances/reboot 等权限 | 补全执行角色权限,遵循最小权限 |
| VPC 内部 Lambda 调用 EC2 API 超时 | VPC 内 Lambda 没有出口访问公网 | 配置 NAT 网关,或者使用 VPCEndpoint 访问 EC2 接口 |
常见问题 (FAQ):
Q1:CloudWatch 原生告警就支持 Reboot/Stop 动作,为什么还要写 Lambda? A:原生告警动作适合简单固定恢复;Lambda 可以实现:区分不同指标执行不同动作、打故障标签、组合多指标判断、输出详细日志、对接第三方通知系统,适合复杂生产自愈场景。
Q2:StatusCheckFailed_System 为什么不能直接 Reboot? A:Reboot 只是操作系统重启,实例仍然运行在原有故障宿主机上;stopstart 会释放物理主机,重新调度到新宿主机,修复硬件层面故障。
Q3:整套自动化链路从异常发生到执行恢复,整体延迟大概多少? A:状态检查指标 1 分钟粒度,连续 2 个周期告警,从故障发生到触发 Lambda 大约 23 分钟;EventBridge 转发事件毫秒秒级别。
Q4:如何避免自动化自愈误操作线上核心业务? A:①IAM 使用标签条件限制仅处理带特定标签的实例;②先在测试实例完整验证;③配置死信队列兜底人工告警;④增加自愈冷却时间,短时间内禁止多次执行恢复动作。
Q5:EC2 实例属于 Auto Scaling 自动伸缩组,这套 Lambda 自愈方案还能用吗? A:不建议。stop/stopstart 动作会被 ASG 检测实例不健康直接终止重建。应该使用 ASG 自身健康检查策略,直接替换故障实例。