4. 预算、预警与配额治理

在 Google Cloud 中,成本失控往往不是“突然多花了一笔钱”,而是缺少一条从“预算阈值触发”到“自动响应”的闭环。预算本身只是监控工具,它不会阻止资源创建;真正能止血的是把预算提醒接入 Pub/Sub,再由 Cloud Run Functions 或 Cloud Run 服务执行配额调整、标签校验、资源停机等动作。本节围绕这条治理链路展开,重点讲清楚每个环节的配置对象、参数含义和判断依据。

一、预算的三种范围与阈值设计

Cloud Billing 预算支持三种范围:Billing account 级(覆盖该结算账号下所有项目)、Project 级(单项目)、Folder 级(组织内文件夹聚合)。生产环境建议至少配置两层:结算账号级做总闸门,项目级做责任到人。预算金额可以设为固定值,也可以基于上一周期实际支出按百分比滚动计算。

阈值规则是预算的核心。每条规则包含“触发百分比”和“触发基准”。基准有两种:Forecasted(预测值)和 Actual(实际值)。例如一条规则设为“Actual 达到 80%”,表示当月实际支出达到预算的 80% 时触发;另一条设为“Forecasted 达到 100%”,表示按当前消费速率预测月底会超支时提前告警。建议配置 50%、80%、100%、120% 四档,前两档用于提醒,后两档用于自动化响应。

预算提醒默认发送给 Billing Account Administrators 和 Billing Account Users。若要让具体负责人收到,需在预算的“Email notifications”中手动添加邮箱,或通过 Pub/Sub 转发到企业 IM/工单系统。

二、从预算到 Pub/Sub:通知链路

预算的 Pub/Sub 通知不是“发一条消息”那么简单,它需要先创建主题、授予权限、再在预算中绑定。关键权限是让 Cloud Billing 的服务账号具备向该主题发布消息的能力。配置顺序如下:

# 1. 创建主题
gcloud pubsub topics create budget-alerts

# 2. 允许 Cloud Billing 发布消息
gcloud pubsub topics add-iam-policy-binding budget-alerts \
  --member="serviceAccount:billing-budget-alert@system.gserviceaccount.com" \
  --role="roles/pubsub.publisher"

# 3. 在预算中绑定该主题(控制台或 API)
#    预算 -> Notifications -> Connect a Pub/Sub topic

绑定后,每次阈值触发都会向主题推送一条 JSON 消息,字段包括 budgetDisplayName、costAmount、budgetAmount、alertThresholdExceeded、currencyCode 等。下游函数据此判断“是提醒还是执行”。

三、自动化响应的三种典型动作

收到 Pub/Sub 消息后,响应函数通常做三类动作:

  • 通知类:把消息转发到 Slack、钉钉或工单系统,附带项目 ID、当前花费和阈值,便于人工介入。
  • 限制类:调用 Cloud Quotas API 降低特定配额,例如把某项目的 compute.googleapis.com/cpus 从 100 降到 20,阻止继续扩容。
  • 停机类:对非生产项目批量停止 Compute Engine 实例或删除临时资源,适用于沙箱、测试环境。

下面这张图展示了从预算触发到自动化响应的完整信号链,包含阈值判断、Pub/Sub 分发和三类响应分支。

Cloud Billing 预算 范围:Billing / Project 金额:¥50,000 / 月 阈值规则 Actual ≥ 50% → 提醒 Actual ≥ 80% → 预警 Forecast ≥ 100% → 限制 Actual ≥ 120% → 停机 Pub/Sub 主题 budget-alerts JSON 消息推送 Cloud Run Functions 解析消息 → 判断阈值 选择响应分支 ① 通知类响应 Slack / 钉钉 / 工单 附带项目 ID、花费、阈值 适用:50% / 80% 档 ② 限制类响应 Cloud Quotas API 降配 cpus: 100 → 20 适用:Forecast ≥ 100% ③ 停机类响应 停止非生产 VM 实例 删除临时磁盘 / IP 适用:Actual ≥ 120% 响应结果回写:调整预算 / 恢复配额 / 记录审计日志 形成“触发—响应—复盘—调参”闭环

四、配额限制:比预算更硬的约束

预算提醒是“事后感知”,配额才是“事前约束”。Google Cloud 的配额分为速率配额(如每秒 API 调用数)和分配配额(如某区域 CPU 总数)。在成本治理中,最常用的是对 compute.googleapis.com/cpus、compute.googleapis.com/instances、run.googleapis.com/container_instances 等分配配额设置上限。

配额调整可以通过控制台“IAM 与管理 → 配额”页面操作,也可以用 Cloud Quotas API 自动化。下面是一个用 API 降低项目 CPU 配额的示例:

# 查询当前配额
gcloud alpha quotas info describe compute.googleapis.com/cpus \
  --project=my-sandbox --region=asia-east1

# 提交降配请求(示例值)
gcloud alpha quotas update compute.googleapis.com/cpus \
  --project=my-sandbox --region=asia-east1 \
  --value=20 --preferred-value=20

需要注意:配额调整不是瞬时生效,部分配额需要审批。因此自动化响应中应把“降配”设计为幂等操作,并在日志中记录请求 ID,便于追踪是否真正生效。

五、治理流程的闭环设计

把上述环节串起来,一个可落地的预算超支治理流程包含五个阶段:预算定义 → 阈值触发 → Pub/Sub 分发 → 分级响应 → 复盘调参。其中“分级响应”是核心:低阈值只通知,中阈值降配额,高阈值停机。每次响应后,函数应把结果写入 Cloud Logging,并可选地更新预算金额或阈值,避免同一周期内反复触发。

自动化停机前务必确认目标项目已打上 env: sandbox 或 env: test 标签,并通过标签过滤避免误停生产资源。建议先在 dry-run 模式下运行函数,只记录“将要执行的动作”而不真正调用停机 API。

六、一个可参考的响应函数判断逻辑

下面用伪代码展示函数如何根据 Pub/Sub 消息中的 alertThresholdExceeded 字段选择动作。该字段是一个 0~1 之间的小数,例如 0.8 表示达到 80%。

def handle_budget_alert(event, context):
    data = json.loads(base64.b64decode(event['data']))
    threshold = data.get('alertThresholdExceeded', 0)
    project = data.get('projectId')
    cost = data.get('costAmount')
    budget = data.get('budgetAmount')

    if threshold >= 1.2:
        stop_non_prod_instances(project)   # 停机
    elif threshold >= 1.0:
        reduce_cpu_quota(project, 20)      # 降配额
    elif threshold >= 0.8:
        notify_channel(project, cost, budget)  # 预警
    else:
        log_only(project, cost)            # 仅记录

这段逻辑的关键在于:阈值判断必须放在函数内部,而不是依赖预算侧的多条规则分别触发不同主题。统一入口、统一判断,才能保证响应顺序和幂等性。实际部署时,建议把 stop_non_prod_instances 和 reduce_cpu_quota 拆成独立函数,通过 Pub/Sub 的多个订阅分别消费,避免单点故障。

最后,治理流程不是一次配置就结束。每月应复盘一次:哪些阈值被频繁触发、哪些响应动作真正生效、预算金额是否需要调整。把复盘结果回写到预算和配额配置中,才能让这套机制持续贴合业务实际。