VicroCode
让代码创造价值
VicroCode是一个轻量级代码在线发布、交易平台,开箱即用,免部署、免服务器、免备案,支持接入智能体、通用管理系统、游戏等多种项目
稍候片刻,您可先学习AI编程手册
正在加载中...

市场信息

[分享创造] AWS Lightsail 全球多区域共享流量监控与自动停机部署手册

我用 AWS 的 lightsail ,每个 VPS 的流量是叠加的;但是 AWS 本身没有提供一种功能: 即流量快要用完了,自动停机 ;我找了一下网上的脚本,基本上都是基于单台 VPS 的监控,于是自己动手实现一个监控及报警方案;以下内容是边操作边用 AI 记录,最后 AI 整理完成的文档;

www.v2ex.com · 2026-10-22T00:12:05+00:00

我用 AWS 的 lightsail ,每个 VPS 的流量是叠加的;但是 AWS 本身没有提供一种功能: 即流量快要用完了,自动停机 ;我找了一下网上的脚本,基本上都是基于单台 VPS 的监控,于是自己动手实现一个监控及报警方案;以下内容是边操作边用 AI 记录,最后 AI 整理完成的文档;我 Review 了一遍,是无误的: 本文档提供了一套基于 AWS Lambda + Amazon SNS + Amazon EventBridge 的自动化流量监控方案。核心特性 全球区域自适应:内置全球 15 个 Lightsail 可用区并发扫描,后续跨区迁移、新增或删除 VPS 均无需修改任何代码。

区域流量池共享计算:严格对齐 AWS 计费规则,自动累加同区域内所有 VPS 的流量配额与实际使用量(入站 + 出站)。首月配额按天折算:自动识别当月新建的实例,按当月剩余时间比例精准折算可用免费配额。

防天价账单保护:当某区域总使用量超过该区域总配额的 95% 时,自动强制关停该区域所有实例,并通过 SNS 发送汇总邮件告警。 lambda 在一定额度内是免费的;这个小监控脚本消耗非常少,是 100%免费额度内的 第一步:配置 SNS 邮件告警通道 登录 AWS 控制台,进入 Simple Notification Service (SNS)(建议选择 us-east-1 区域)。

创建主题 (Topic): 左侧菜单点击 主题 (Topics) -> 创建主题 (Create topic)。类型:选择 标准 (Standard)。

名称:输入 lightsailmonitor ,滚动到底部点击 创建主题。记录 ARN:复制页面中生成的主题 ARN (格式为:arn:aws:sns:us-east-1:你的账号 ID:lightsailmonitor )。

注意:不要复制后面带冒号和随机字符串的订阅 ARN 。创建邮件订阅 (Subscription): 在该主题页面下方,点击 创建订阅 (Create subscription)。

协议 (Protocol):选择 Email 。终端节点 (Endpoint):输入接收告警的电子邮箱地址,点击 创建订阅。

确认订阅:前往你的邮箱,打开来自 AWS Notifications 的邮件,点击正文中的 Confirm subscription 链接完成绑定。第二步:创建并配置 Lambda 函数 进入 AWS Lambda 控制台(建议与 SNS 同在 us-east-1 区域),点击 创建函数 (Create function)。

基础设置: 选择 从头开始创作 (Author from scratch)。函数名称:lightsailmonitor 运行时 (Runtime):选择最新版本的 Python (如 Python 3.12 / 3.13 / 3.14 )。

点击右下角 创建函数。调整超时时间与内存(必做): 由于需要并发扫描全球 15 个区域,耗时通常在 5~9 秒左右(超过默认的 3 秒限制)。

在函数页面点击 配置 (Configuration) -> 常规配置 (General configuration) -> 编辑 (E dit)。内存 (Memory):建议设置为 256 MB 或 512 MB 。

超时 (Timeout):修改为 0 分 30 秒,点击 保存。第三步:配置 IAM 执行角色权限 Lambda 需要跨全球区域读取、关停 Lightsail 实例以及向 SNS 发送通知的权限。

在 Lambda 函数的 配置 (Configuration) -> 权限 (Permissions) 页面,点击“执行角色 (Execution role)”下方的角色名称链接,进入 IAM 控制台。点击 添加权限 (Add permissions) -> 创建内联策略 (Create inline policy)。

点击右上角切换到 JSON 视图,清空原有内容并粘贴以下最小权限策略(支持全区域操作): { "Version": "2012-10-17", "Statement": [ { "Sid": "LightsailGlobalMonitorAndStop", "Effect": "Allow", "Action": [ "lightsail:GetInstances", "lightsail:GetInstance", "lightsail:GetInstanceMetricData", "lightsail:StopInstance" ], "Resource": "*" }, { "Sid": "SNSPublishAlert", "Effect": "Allow", "Action": [ "sns:Publish" ], "Resource": "arn:aws:sns:*:*:lightsailmonitor" } ] } 4.点击 下一步 (Next),策略名称填入 LightsailGlobalMonitorPolicy ,点击 创建策略 (Create policy)。

第四步:部署核心监控代码 回到 Lambda 函数的 代码 (Code) 选项卡。将下方完整代码粘贴到 lambda_function.py 中( 注意核对第 28 行的 SNS_TOPIC_ARN 是否与你第一步创建的一致 ): import json import boto3 import calendar import os from datetime import datetime, date, time, timedelta from concurrent.futures import ThreadPoolExecutor # 内置全球所有支持 Lightsail 的 AWS 区域(免去 GetRegions 权限要求) # 注:如果某个默认未启用的区域(如雅加达 ap-southeast-3 )报错烦人,可直接从列表中注释掉 LIGHTSAIL_REGIONS = [ 'ap-northeast-1', # 日本 (东京) 'ap-northeast-2', # 韩国 (首尔) 'ap-southeast-1', # 新加坡 'ap-southeast-2', # 澳大利亚 (悉尼) 'ap-southeast-3', # 印度尼西亚 (雅加达) 'ap-south-1', # 印度 (孟买) 'us-east-1', # 美国东部 (弗吉尼亚北部) 'us-east-2', # 美国东部 (俄亥俄) 'us-west-2', # 美国西部 (俄勒冈) 'ca-central-1', # 加拿大 (中部) 'eu-central-1', # 欧洲 (法兰克福) 'eu-west-1', # 欧洲 (爱尔兰) 'eu-west-2', # 欧洲 (伦敦) 'eu-west-3', # 欧洲 (巴黎) 'eu-north-1' # 欧洲 (斯德哥尔摩) ] # 请填写你的 SNS 主题 ARN (注意:到主题名称为止,不要包含末尾的订阅 ID ) SNS_TOPIC_ARN = 'arn:aws:sns:us-east-1:xxxxxx:lightsailmonitor' # 触发强制关机的流量阈值比例( 0.95 代表 95%) QUOTA_THRESHOLD = 0.95 def push_notification(arn, msg): """发送 SNS 告警通知(自动从 ARN 提取对应区域)""" sns_region = arn.split(':')[3] sns_client = boto3.client('sns', region_name=sns_region) sns_client.publish( TopicArn=arn, Message=msg, Subject='[AWS Alert] Lightsail Region Network Quota Exceeded' ) def get_current_month_first_day_zero_time(): today = date.today() first_day = today.replace(day=1) return datetime.combine(first_day, time.min) def get_current_month_last_day_last_time(): today = date.today() last_day = today.replace(day=calendar.monthrange(today.year, today.month)[1]) return datetime.combine(last_day, time(23, 59, 59)) def stop_instance(client, instance_name): client.stop_instance( instanceName=instance_name, force=True ) def list_instances(client): instances_list = [] paginator = client.get_paginator('get_instances') for page in paginator.paginate(): for instance in page['instances']: instances_list.append(instance['name']) return instances_list def get_month_dto_quota(client, instance_name): """获取单台实例当月可用配额(当月新建实例按剩余时间比例折算)""" response = client.get_instance(instanceName=instance_name) dto_quota = response['instance']['networking']['monthlyTransfer']['gbPerMonthAllocated'] current_datetime = datetime.now() instance_created_datetime = response['instance']['createdAt'] if (instance_created_datetime.year == current_datetime.year) and (instance_created_datetime.month == current_datetime.month): month_ts = get_current_month_last_day_last_time().timestamp() - get_current_month_first_day_zero_time().timestamp() instance_valide_ts = get_current_month_last_day_last_time().timestamp() - instance_created_datetime.timestamp() dto_quota = (instance_valide_ts / month_ts) * dto_quota print(f"[{instance_name}] created in current month, prorated quota: {dto_quota:.2f}GB") else: print(f"[{instance_name}] created in previous month, full quota: {dto_quota}GB") return dto_quota def get_instance_data_usage(client, instance_name, data_type): """获取单台实例当月累计流量( Bytes )""" start_time_str = get_current_month_first_day_zero_time().strftime('%Y-%m-%dT%H:%M:%SZ') end_time_str = get_current_month_last_day_last_time().strftime('%Y-%m-%dT%H:%M:%SZ') response = client.get_instance_metric_data( instanceName=instance_name, metricName=data_type, period=6 * 600 * 24, unit='Bytes', statistics=['Sum'], startTime=start_time_str, endTime=end_time_str ) data_points = response['metricData'] total_data_usage = sum([data_point['sum'] for data_point in data_points]) print(f"[{instance_name}] total {data_type} usage: {total_data_usage}") return total_data_usage def check_single_region(region): """按区域汇总所有 Lightsail 实例的共享流量配额与总使用量""" try: client = boto3.client('lightsail', region_name=region) instances = list_instances(client) if not instances: return print(f"=== Found {len(instances)} instance(s) in {region}: {instances} ===") region_total_quota = 0 region_total_usage = 0 instance_details = [] # 1. 遍历区域内所有实例,累加总配额和总使用量 for i in instances: quota = get_month_dto_quota(client, i) * 1000 * 1000 * 1000 usage = get_instance_data_usage(client, i, "NetworkOut") + get_instance_data_usage(client, i, "NetworkIn") region_total_quota += quota region_total_usage += usage detail_str = f" - {i}: usage {usage / (1000**3):.2f} GB / quota {quota / (1000**3):.2f} GB ({(usage/quota)*100:.2f}%)" instance_details.append(detail_str) # 2. 计算整个区域的共享流量使用百分比 usage_percent = (region_total_usage / region_total_quota) * 100 if region_total_quota > 0 else 0 summary_msg = ( f"Region: {region}\n" f"Instances Count: {len(instances)}\n" f"Region Total Usage: {region_total_usage} Bytes ({region_total_usage / (1000**3):.2f} GB)\n" f"Region Total Quota: {region_total_quota} Bytes ({region_total_quota / (1000**3):.2f} GB)\n" f"Region Shared Usage Percent: {usage_percent:.2f}%\n" f"Instance Breakdown:\n" + "\n".join(instance_details) ) print(summary_msg) # 3. 如果区域总使用量超过区域总配额的阈值(默认 95%),关停该区域所有实例并发送告警 if (region_total_quota * QUOTA_THRESHOLD) 日志组 (Log groups) -> 点击 /aws/lambda/lightsailmonitor 。

在“保留 (Retention)”设置中,建议将其设置为 1 个月 (30 days) 或 7 天,避免长期运行积累过多历史日志。关于删除实例的计费陷阱(重要): 在 AWS Lightsail 中,停止( Stopped ) 状态的实例依然会保留其月度流量配额供同区域其他机器共享。

但如果在月中直接 删除( Deleted ) 了某台跑过流量的实例,该实例贡献的配额会从区域流量池中扣除,而已消耗的流量可能会引起剩余机器超额。因此,若某台机器不再使用且当月跑了较多流量,建议先关机( Stop )保留到月底,下个月初再删除。

AWS lightsail 的流量,是双向计算的,出和入是都计算的;比如你一台 VPS 流量是 2000GB ;这个月出 500GB ,入 1600GB ,那么总流量是 2100GB ,就超出限额了;

返回 AI 市场导读

来源:v2ex.com