作为一名开发者,最心痛的时刻莫过于月底收到 AWS 账单时,发现几台测试用的 EC2 实例在下班后和周末一直开着空跑。
为了省钱,我们通常希望实现:“每天下班后(如 18:00)和凌晨(如 02:00)自动关机”。
虽然 EventBridge Scheduler 可以直接调用 EC2 关机接口,但它要求硬编码 Instance ID。一旦你新增了服务器,又得去改计划,非常麻烦。本文将介绍一种更优雅、更具扩展性的方案:利用标签 (Tag) 管理实例,配合 Lambda 脚本实现自动化。
方案架构
- EventBridge Scheduler: 也就是“闹钟”,负责在指定时间(支持本地时区)触发任务。
- AWS Lambda: 也就是“执行者”,运行一段 Python 脚本,查找带有特定标签的实例并关闭它们。
- EC2 Tags: 给需要管理的机器打上标签(例如
AutoStop: true),实现“即打即用”。
第一步:创建 Lambda 函数 (执行大脑)
我们需要一个 Python 脚本来扫描并关闭服务器。
- 登录 AWS 控制台,进入 Lambda 服务。
- 点击 Create function。
- Name: 输入
StopEC2ByTag。 - Runtime: 选择 Python 3.9 (或更新版本)。
- 点击 Create function。
1. 编写代码
在 Code source 区域,打开 lambda_function.py,粘贴以下代码:
import boto3
# --- 配置区域 ---
# 设置你要查找的标签 Key 和 Value
# 只有打上这个标签的机器才会被关机
TAG_KEY = 'AutoStop'
TAG_VALUE = 'true'
# 设置地区 (例如东京是 ap-northeast-1)
REGION = 'ap-northeast-1'
# ----------------
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name=REGION)
print(f"任务开始:正在查找标签为 {TAG_KEY}={TAG_VALUE} 的运行中实例...")
# 1. 根据标签查找所有 "running" 状态的实例
response = ec2.describe_instances(
Filters=[
{'Name': f'tag:{TAG_KEY}', 'Values': [TAG_VALUE]},
{'Name': 'instance-state-name', 'Values': ['running']}
]
)
instance_ids = []
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instance_ids.append(instance['InstanceId'])
# 2. 执行关机操作
if len(instance_ids) > 0:
print(f"发现目标实例,准备关闭: {instance_ids}")
ec2.stop_instances(InstanceIds=instance_ids)
return f"成功关闭了 {len(instance_ids)} 台实例"
else:
print("未发现符合条件的运行中实例,无需操作。")
return "没有实例被关闭"
点击 Deploy 保存。
2. 赋予权限 (关键步骤)
默认情况下,Lambda 没有权限操作 EC2。
- 点击 Configuration (配置) -> Permissions (权限)。
- 点击 Execution role 下方的角色名称(跳转到 IAM)。
- 点击 Add permissions -> Attach policies。
- 搜索
EC2Full,勾选 AmazonEC2FullAccess 并添加。- 注:生产环境建议配置更精细的 Policy(仅允许 DescribeInstances 和 StopInstances),但在个人开发环境,FullAccess 最省事。
第二步:配置 EventBridge Scheduler (定时闹钟)
AWS 新出的 Scheduler 支持时区设置,我们再也不用痛苦地换算 UTC 时间了。
- 进入 EventBridge 服务,点击左侧的 Schedules。
- 点击 Create schedule。
1. 设置时间表
- Schedule name:
Daily-EC2-AutoStop - Schedule pattern: 选择
Recurring schedule(重复计划)。 - Schedule type: 选择
Cron-based schedule。 - Timezone (重点): 下拉选择 Asia/Tokyo (或者你所在的 Asia/Shanghai)。
- 这样上面的 2 和 18 就是指本地时间。
Cron expression:
0 2,18 * * ? *
(这代表在 2点 和 18点 的 0分触发)
2. 选择目标
- Target API: 选择 AWS Lambda -> Invoke。
- Function: 选择刚才创建的
StopEC2ByTag。 - 一直点击 Next 直到完成创建。
第三步:测试与验证
现在配置已经完成,如何验证它是否有效?
- 给实例打标签:去 EC2 控制台,找一台测试机,添加标签 Key:
AutoStop, Value:true。 - 手动测试 Lambda:在 Lambda 页面点击 Test 按钮。
- 如果代码显示
成功关闭了 1 台实例,且 EC2 真的关机了,说明脚本和权限没问题。
- 如果代码显示
- 等待定时触发:到了设定的时间(18:00 或 02:00),去 Lambda -> Monitor -> View CloudWatch logs 查看日志。
- 如果看到自动触发的日志,说明计划任务配置成功。
常见问题 (FAQ)
Q: 这个方案收费吗?
几乎完全免费。
- EventBridge Scheduler: 每月前 1400 万次触发免费。
- Lambda: 每月前 100 万次请求免费。
- 你的用量(每天2次 = 每月60次)连免费额度的零头都不到。
Q: 为什么不直接用 Scheduler 里的 "EC2 StopInstances"?
Scheduler 原生支持的 StopInstances 需要你填入具体的 Instance ID(如 i-0123456)。
这意味着如果你新开了一台服务器,你必须记得回来修改定时计划,非常容易忘。
使用 Lambda + 标签 的方案,你只需要给新机器打个标签,它就会自动进入管理队列,实现“一劳永逸”。
Q: 我想加个早上自动开机怎么办?
原理一样!
- 复制一份 Lambda 代码,把
ec2.stop_instances改成ec2.start_instances,查找状态由'running'改为'stopped'。 - 在 Scheduler 里新建一个计划(比如早上 9 点),调用这个开机 Lambda 即可。