Azure Cost Management 与 AKS Cost Analysis
平台组在 AKS 门户里看到了 namespace 成本,财务导出的订阅账单却只有 Azure 资源;两边总额接近,按团队汇总后仍有差异。有人准备把门户截图当月度分摊依据,另一个人则想用 FOCUS export 直接还原 Pod 成本。两个方案都跨过了关键边界:AKS Cost Analysis 是经过 Azure 发票数据对账的 Kubernetes 成本视图,Cost Management export 是账单数据交付链,它们相关,但不是同一张可互换的明细表。
真正可运营的方案要保留两条证据链。集群侧回答“成本落到哪些 cluster、namespace 和资产类别”;账单侧回答“Azure 对哪些资源、折扣和计费周期收了多少钱”。团队分摊层再固定口径、保存 lineage,并把 Idle、System、Service 与 Unallocated 留在账本中。
先认清两条数据链
启用 Cost Analysis 后,AKS 在集群内部署基于 OpenCost 的 agent,收集 Kubernetes 用量和 Azure 资产 ARM ID,再与 Azure invoice data 对账。Microsoft Cost Management 当前明确提供三类订阅范围视图:
Kubernetes clusters:按集群聚合,并可进入 namespace 或资产分析。Kubernetes namespaces:聚合 namespace,同时保留 Idle、System、Service 与 Unallocated。Kubernetes assets:按 Compute、Networking、Storage、Service 查看 Azure 资产成本。
这并不等于官方已经提供 Deployment、StatefulSet、Pod 或任意 workload label 级的 Cost Management 账单键。需要更细粒度时,应使用 OpenCost、Kubecost 或自建采集链补充运行侧证据,再与 Azure 账单对账,不能虚构门户已有字段。
Cost Management export 则把 Actual、Amortized 或 FOCUS cost and usage details 周期性写入 Azure Blob Storage。FOCUS 当前交付为 1.2-preview,包含规范字段与 Azure x_ 扩展,但不能把 AKS namespace 视图等同于 FOCUS allocation 字段。架构上应保留:
AKS API / Azure assets → Cost Analysis agent → cluster / namespace / asset views
Azure billing scopes → Cost Management export → Blob / Fabric / warehouse
\ /
governed allocation view启用前先证明平台条件成立
集群必须处于 Standard 或 Premium tier,使用 managed identity;Free tier 和 virtual nodes 不支持。Azure CLI 至少为 2.61.0。Kubernetes cost views 还受计费协议限制,当前支持 Enterprise Agreement 与 Microsoft Customer Agreement offer,不能只凭“有 AKS”判断功能一定可用。
先用只读命令保存基线:
az version --query '"azure-cli"' -o tsv
az aks show \
--resource-group <resource-group> \
--name <cluster-name> \
--query '{tier:sku.tier,identity:identity.type,powerState:powerState.code,nodeResourceGroup:nodeResourceGroup}' \
-o yaml
az account show --query '{subscription:id,tenant:tenantId,user:user.name}' -o yaml预期 tier 为 Standard 或 Premium,identity 不是空值,集群处于 Running。执行身份还要能更新 AKS 集群;只查看成本的人员则优先授予 Cost Management Reader 或 Reader,不要为了看报表授予 Owner。
受限网络集群应先核对 AKS Cost Analysis 所需 FQDN。若 Azure Resource Manager 等出口被阻断,控制面可能显示启用成功,agent 却无法补齐资产 ID。
逐步启用 Cost Analysis
先在隔离的非生产集群执行:
az aks update \
--resource-group <resource-group> \
--name <cluster-name> \
--enable-cost-analysis命令返回的 provisioningState 应为 Succeeded。随后检查 add-on、agent 和新身份,而不是立刻用“门户没有数据”判断失败:
az aks show \
--resource-group <resource-group> \
--name <cluster-name> \
--query '{state:provisioningState,addonProfiles:addonProfiles}' -o json
kubectl get pods -A | grep -i cost
kubectl get events -A --sort-by=.lastTimestamp | grep -Ei 'cost|oom|pending'启用会创建名为 cost-analysis-identity 的 managed identity,授予它读取集群 node resource group 的权限,并关联到 node pools。节点上原来依赖“默认 managed identity”的脚本此后可能选错身份,必须显式指定资源 ID:
az login --identity --resource-id <managed-identity-resource-id>这不是细枝末节。若节点初始化、镜像拉取辅助脚本或存储挂载脚本默认选中了 cost identity,故障会表现为启用成本功能后业务节点突然无权访问原资源。
建立可解释的验证工作负载
选择已有余量的测试集群,创建两个 namespace。一个承载稳定 requests 的工作负载,另一个故意不提交业务 Pod,用于观察业务分摊和 idle/system 项是否被区分:
apiVersion: v1
kind: Namespace
metadata:
name: cost-lab-a
---
apiVersion: v1
kind: Namespace
metadata:
name: cost-lab-empty
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: allocation-probe
namespace: cost-lab-a
spec:
replicas: 2
selector:
matchLabels:
app: allocation-probe
template:
metadata:
labels:
app: allocation-probe
cost-center: platform-lab
spec:
containers:
- name: pause
image: registry.k8s.io/pause:3.10.1
resources:
requests: {cpu: 100m, memory: 64Mi}
limits: {cpu: 100m, memory: 64Mi}kubectl apply -f aks-cost-probe.yaml
kubectl -n cost-lab-a rollout status deployment/allocation-probe --timeout=120s
kubectl -n cost-lab-a get pod -o wide
kubectl -n cost-lab-a get pod -o custom-columns='NAME:.metadata.name,NODE:.spec.nodeName,CPU:.spec.containers[*].resources.requests.cpu,MEM:.spec.containers[*].resources.requests.memory'保存 cluster resource ID、node resource group、namespace、Pod UID、节点名和验证窗口。门户数据需要采集和账单处理时间;官方说明前一日成本可能在 24 小时后才稳定,因此验收应记录首条数据出现时间和稳定时间,而不是声称固定分钟级 SLA。
正向实验:从订阅总额下钻到 namespace 与资产
数据稳定后,在 Cost Management 的 subscription scope 依次打开 Kubernetes clusters、Kubernetes namespaces 和 Kubernetes assets。正向证据至少包括:
目标集群出现在 cluster 视图。cost-lab-a 出现在 namespace 视图,空闲容量没有被强行全部归给它。Compute、Networking、Storage、Service 能回到对应 Azure 资产类别。
Idle、System、Service 和 Unallocated 没有被过滤成零。同一 scope、计费周期、币种和成本口径下,分类合计能够回到 Cost Management 总额。
默认视图使用 actual cost;reservation 或 savings plan 需要以 amortized cost 展开时,必须把口径作为报表字段保存。一个月用 actual、下个月用 amortized,会把采购时点费用和使用期摊销混在一起,差异无法用 namespace 行解释。
可用守恒式做门禁:
namespace allocated
+ idle
+ system
+ service
+ unallocated
= cluster cost under the same scope, currency and cost basis允许账单迟到和舍入形成受控差异,但差异必须有阈值、原因代码和回补流程,不能用人工调平覆盖。
反向实验:让 agent 资源不足
Cost Analysis agent 的内存可粗略估算为 200 MB + 0.5 MB × container 数,当前上限 4 GB,约支持 7,000 containers;这些是会变化的容量信号,不是无限承诺。不要在生产集群制造 OOM。先读取 agent 的 requests、limits 与实际峰值,在测试集群通过受控扩容或临时降低 limit 复现:
kubectl get pods -A | grep -i cost
kubectl describe pod -n <cost-namespace> <cost-agent-pod>
kubectl top pod -n <cost-namespace> <cost-agent-pod> --containers
kubectl get events -n <cost-namespace> --field-selector reason=OOMKilling反向证据是 OOMKilled、重启次数增加、采集窗口缺口或 namespace 视图延迟,而不是“成本变成零”。恢复官方管理的资源配置后重新观察;若 add-on 会自动调和手工修改,应把该现象记录为平台所有权边界。生产容量评审至少跟踪容器数、agent working set、重启、Pending/OOM、视图缺口和账单迟到。
把账单交付到受控存储
需要审计、数仓或跨团队 showback 时,在 Cost Management 的目标 billing/subscription scope 创建 Export:选择 Actual、Amortized 或 Cost and usage details (FOCUS),目标使用 Azure Blob Storage,格式优先 Parquet + Snappy;CSV 可使用 Gzip。文件分区默认开启,日更 overwrite 会用更新后的文件覆盖该日版本,消费层必须按 export run、分区和账期做幂等加载。
Cost Management exports 支持计划任务、Run now 与历史重跑。FOCUS export 不支持 management group scope,MOSP billing scopes/subscriptions 也不支持 FOCUS dataset。门户通常可取约 13 个月,REST API 在数据仍可用时可追溯更长窗口;长期保留必须由团队自己的存储策略承担。
导出后的第一步不是做图表,而是保存 manifest:
export name
scope + enrollment/agreement type
dataset + schema version
actual / amortized / FOCUS basis
storage account + container + path
run ID + processing window
file count + bytes + row count若存储账号启用 firewall,要确认 Cost Management export 的 managed identity 被纳入 trusted access,并同时检查 Storage Blob Data Contributor、网络与加密密钥。创建者删除或修改 export 时,系统尝试移除相关角色;执行者缺少 Microsoft.Authorization/roleAssignments/delete 会留下孤儿授权,需要人工核销。
让门户视图与 export 可对账但不混表
FOCUS 1.2-preview 的 BilledCost、EffectiveCost、ChargePeriod*、BillingPeriod* 与 x_ 扩展服务于账单规范化。AKS namespace 视图服务于 Kubernetes 分摊。建立派生层时,应保留两个 source contract:
-- 字段名按实际导出 schema 适配,禁止直接假定所有版本一致
SELECT
ProviderName,
BillingAccountId,
SubAccountId,
ChargePeriodStart,
ChargePeriodEnd,
BilledCost,
EffectiveCost,
BillingCurrency,
ResourceId,
Tags
FROM <azure_focus_external_table>
WHERE ChargePeriodStart >= <window_start>
AND ChargePeriodStart < <window_end>;另一张 allocation 表保存 cluster、namespace、asset category、allocated/idle/system/service/unallocated、口径和采集窗口。只有经过 resource ID、scope 和时间窗验证的关系才能 join。不能因为两张表总额接近,就把 namespace 写回任意 FOCUS 行。
常见失败沿链路定位
| 现象 | 先看什么 | 常见原因 | 处理 |
|---|---|---|---|
az aks update 拒绝 | tier、identity、CLI、权限 | Free tier、无 managed identity、CLI 过旧 | 升级 tier/CLI,配置 identity 与最小更新权限 |
| agent Pending/OOM | Pod events、limit、容器数 | 节点余量不足或规模接近上限 | 增加系统池余量,降低单集群规模,建立容量告警 |
| 门户无 Kubernetes 视图 | agreement、角色、采集时间 | offer 不支持、只读权限缺失、数据未稳定 | 核对协议与 subscription scope,等待并记录窗口 |
| namespace 合计不守恒 | Idle/System/Service/Unallocated | 过滤了非业务类别或口径混用 | 恢复全部类别,固定 actual/amortized |
| Export 无文件 | run history、storage RBAC、firewall | managed identity 无写权限或网络阻断 | 核对运行历史、trusted access 与角色 |
| 文件有数据但报表断裂 | schema version、overwrite、分区 | 消费者绑定物理列或重复加载 | 加 adapter view,按 run/partition 幂等处理 |
| 启用后节点脚本鉴权失败 | managed identity 选择 | 默认 identity 改变 | 显式传 --resource-id |
权限与敏感数据分四层治理
集群 add-on 管理员、Cost Management viewer、Export 管理员、原始 Blob 消费者应是不同角色。应用团队只读取按 subscription、cluster 或 namespace 授权的派生视图;真实折扣、reservation、资源 ID、成本中心、客户和 reseller 字段留在 FinOps 数据域。
Export 可能包含 account owner email、资源组、完整 ARM ID 和标签。namespace 与标签也可能暴露客户、工单或人员信息。进入集群前就要通过命名和 admission 规则阻断敏感值,进入存储后再用行列级权限、私有端点、加密和查询审计隔离。脱敏不能只删显示名,仍可反查组织关系的 ARM ID 和标签组合也属于敏感数据。
升级、回滚与退出
升级 AKS、Cost Analysis add-on 或 export schema 时,先冻结一段稳定窗口,在旧、新派生视图上比较行数、总额、分类守恒、actual/amortized 和迟到修正,再切换消费者。不要让 FOCUS schema 版本变化直接击穿团队报表;物理文件先进入 adapter view。
退出按证据顺序执行:
保存最后一个稳定账期的 cluster、namespace、asset 视图和 export 对账快照。关闭 add-on:
az aks update \
--resource-group <resource-group> \
--name <cluster-name> \
--disable-cost-analysis确认 agent 已清理,集群可按需调整 tier;检查 cost-analysis-identity 及 node resource group 读取角色是否仍被其他对象引用后再核销。禁用或删除 export,检查 run history 不再产生新文件,并撤销 managed identity 的 Blob 角色。按财务和审计策略保留或删除历史 Blob、外部表、派生视图和缓存,而不是假定关闭 add-on 会删除历史账单。
删除验证 namespace:
kubectl delete namespace cost-lab-a cost-lab-empty
kubectl get namespace cost-lab-a cost-lab-empty最后一项验收不是“页面消失”,而是新采集停止、历史证据可追溯、权限已核销、替代报表已切换,且财务账本没有因关闭 Kubernetes 视图而失去入口。
官方操作入口可交叉核对 AKS Cost Analysis、Kubernetes 成本视图、FOCUS schema 与 Cost Management exports。
