深色模式
云账单与标签
摘要:没有标签的云账单只是一串数字,无法回答「哪个团队花了多少钱」。本文给出一套最小可用的标签体系、强制打标的落地方法,以及如何用账单 API 做分账与异常检测。
适用环境
bash
# 需要账单(Billing / Cost Explorer)只读权限 + 标签管理权限
which jq python3
aws iam list-attached-user-policies --user-name "$(aws sts get-caller-identity --query Arn --output text | awk -F/ '{print $NF}')" 2>/dev/null | head1
2
3
2
3
操作步骤
一、设计标签体系(字段越少越好)
标签不是越多越好,字段太多没人会认真填。建议只保留 5 个:
| 标签键 | 取值示例 | 用途 |
|---|---|---|
env | prod / staging / test / dev | 环境分账 |
app | order / payment / gateway | 应用/服务分账 |
owner | 团队或负责人标识 | 找人 |
cost_center | cc-001 | 财务分摊 |
managed_by | terraform / manual | 区分是否被 IaC 管理 |
注意
标签键的大小写和拼写必须完全一致。Env、env、ENV 在账单里是三个不同的标签,会导致分账数据被割裂。用策略强制小写是最省心的做法。
二、强制打标:三道防线
bash
# 1) IaC 里统一注入(最有效,覆盖率接近 100%)
# Terraform provider 的 default_tags 可自动给所有资源打标签
cat >> provider.tf <<'EOF'
provider "aws" {
region = "ap-east-1"
default_tags {
tags = {
env = "prod"
managed_by = "terraform"
}
}
}
EOF
terraform plan | grep -c "tags"1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
json
// 2) 策略层强制:创建资源时必须带 env 与 owner,否则拒绝
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Deny",
"Action": ["ec2:RunInstances", "rds:CreateDBInstance", "s3:CreateBucket"],
"Resource": "*",
"Condition": {
"Null": {"aws:RequestTag/env": "true"}
}
}]
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
bash
# 3) 事后巡检:定期扫描未打标的资源并通知 owner
aws resourcegroupstaggingapi get-resources \
--tags-per-page 100 \
--query 'ResourceTagMappingList[?length(Tags[?Key==`env`])==`0`].ResourceARN' --output text1
2
3
4
2
3
4
三、激活标签用于账单拆分
标签必须先在账单控制台「激活」为成本分配标签,之后才出现在成本分析里。激活后通常需要一个完整计费周期才能看到历史数据回填。
bash
# 查看哪些标签可作为成本分配维度
aws ce get-tags --time-period Start=2026-09-01,End=2026-10-09 \
--search-string "env"
# 按 env 维度看成本
aws ce get-cost-and-usage \
--time-period Start=2026-09-09,End=2026-10-09 \
--granularity MONTHLY --metrics BlendedCost \
--group-by Type=TAG,Key=env \
--query 'ResultsByTime[].Groups[].[Keys[0],Metrics.BlendedCost.Amount]' --output table1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
四、无标签成本归因
总有资源没打标(历史遗留、手动创建)。先看「未分配」占比:
bash
# 找出没有 env 标签的资源(按服务维度统计数量)
aws resourcegroupstaggingapi get-resources \
--query 'ResourceTagMappingList[?length(Tags[?Key==`env`])==`0`].ResourceARN' \
--output text | tr '\t' '\n' | sed 's/:.*//' | sort | uniq -c | sort -rn | head1
2
3
4
2
3
4
把「未分配成本占比 < 5%」作为治理目标,写进每月例行动作。
五、账单异常检测
bash
# 1) 设置预算告警:超过阈值自动通知
aws budgets create-budget --account-id 123456789012 --budget '{
"BudgetName":"monthly-prod",
"BudgetLimit":{"Amount":"1000","Unit":"USD"},
"TimeUnit":"MONTHLY","BudgetType":"COST",
"CostFilters":{"TagKey":["env"],"TagValue":["prod"]}
}' --notifications-with-subscribers '[
{"Notification":{"NotificationType":"ACTUAL","ComparisonOperator":"GREATER_THAN","Threshold":80,"ThresholdType":"PERCENTAGE"},
"Subscribers":[{"SubscriptionType":"EMAIL","Address":"ops-notify@example.com"}]}
]'
# 2) 每日环比检查:用脚本对比昨天与前 7 天均值
cat > /usr/local/bin/cost-check.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
END=$(date +%F)
START=$(date -d "8 days ago" +%F)
aws ce get-cost-and-usage --time-period Start="$START",End="$END" \
--granularity DAILY --metrics BlendedCost \
--query 'ResultsByTime[].[TimePeriod.Start,Total.BlendedCost.Amount]' --output text
EOF
chmod +x /usr/local/bin/cost-check.sh
/usr/local/bin/cost-check.sh1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
危险
预算告警的阈值要用「百分比 + 金额」双保险。只设金额阈值在业务自然增长时会频繁误报;只设百分比则在绝对金额很小时失去意义。
六、月度分账流程
text
每月 1 号 :导出上月按 env / app / cost_center 的账单
每月 3 号 :与各团队确认异常项(突增服务、未打标资源)
每月 5 号 :输出分摊表给财务,并记录本月优化项1
2
3
2
3
验证
- [ ] 新建资源默认带齐 5 个标签(用 IaC 创建一台测试机验证)
- [ ] 缺少
env标签的创建请求被策略拒绝 - [ ] 成本分析里能按
env维度出数据 - [ ] 未分配成本占比 < 5%
- [ ] 预算告警邮件/通知已成功收到过一次
常见坑
- 标签大小写不统一:
Prod与prod被拆成两份,分账数据失真。 - 打了标签但没激活:控制台里能看到标签,账单里却选不到,白忙一场。
- 只打不治:标签体系上线后没人巡检,半年后新资源又回到裸奔状态。
- 标签承载过多信息:塞进版本号、发布日期等易变信息,导致标签频繁变动、历史分账错乱。
- 预算告警发到没人看的邮箱:通知渠道必须落到有人响应的地方。