4. 容器级成本采集架构:cAdvisor、Metrics Server、Prometheus 采集 CPU/内存/网络/存储的架构设计
容器级成本分摊的精度取决于底层指标采集链路的可靠性。本章深入剖析从 cAdvisor 原始数据暴露、Metrics Server 聚合采样,到 Prometheus 拉取与存储的完整架构,并针对 CPU、内存、网络、存储四类资源的采集路径与常见故障点进行拆解。
4.1 四层采集架构总览
容器资源指标采集遵循“节点代理 → 聚合缓存 → 时序存储 → 成本计算”的分层模型。每一层承担不同的职责,也对应不同的故障模式。
核心原则:成本分摊的准确性不会超过原始采集数据的精度。采集链路上任何一层的丢点、延迟或精度截断,都会直接导致分摊账单出现偏差。
| 层级 | 组件 | 核心职责 | 数据粒度 | 常见故障 |
|---|---|---|---|---|
| L1 节点代理 | cAdvisor (内嵌于 kubelet) | 从 cgroup 读取原始容器资源使用量 | 容器级 / 15s 窗口 | cgroup 统计遗漏、磁盘统计缺失 |
| L2 聚合缓存 | Metrics Server | 采集节点指标并聚合为 Pod 级 Resource Metrics | Pod 级 / 15s~60s | 资源配额不足导致 OOM、节点不可达 |
| L3 时序存储 | Prometheus (Server + kubelet/cadvisor 目标) | 拉取、存储、查询历史指标 | 容器级 / 采集间隔可配置 | 拉取超时、样本重复、存储膨胀 |
| L4 成本计算 | 成本引擎 (基于 Prometheus 数据) | 按 CPU/内存/网络/存储单价计算分摊金额 | 容器级 / 小时或天聚合 | 标签缺失、单价映射错误 |
4.2 CPU 与内存采集路径
CPU 和内存是成本分摊中最核心的两类资源。它们的采集路径有显著差异,故障表现也各不相同。
4.2.1 CPU 采集:从 cgroup 到 Prometheus
- 原始数据源:
/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage— 纳秒级累计计数器。 - cAdvisor 处理:计算 delta(cpuacct.usage) / delta(time) / 核数,得到 CPU 使用率(小数)。
- Prometheus 指标:
container_cpu_usage_seconds_total{container="...", pod="..."}。 - 成本计算:使用
rate(container_cpu_usage_seconds_total[5m])转换为每秒使用量,乘以 CPU 单价。
常见故障:当容器设置
CPU quota 且 CFS 周期 较短时,cAdvisor 可能报告 throttled 时间。如果成本引擎误将 throttled 时间计入使用量,会导致高估实际消耗。建议使用 container_cpu_cfs_throttled_seconds_total 进行修正。
4.2.2 内存采集:RSS 与 WorkingSet 的选择
| 指标 | Prometheus 名称 | 含义 | 适用场景 |
|---|---|---|---|
| RSS | container_memory_rss |
常驻物理内存,不含缓存 | 成本分摊(保守模型) |
| WorkingSet | container_memory_working_set_bytes |
RSS + 活跃缓存,接近实际压力 | 资源配额规划、HPA |
| Usage | container_memory_usage_bytes |
RSS + 所有缓存(含非活跃) | 不推荐用于成本分摊(高估) |
最佳实践:成本分摊场景推荐使用
container_memory_working_set_bytes,因为它更真实反映容器对内存资源的竞争压力。如果使用 RSS,需注意部分语言运行时(如 Java JVM)的堆外内存可能被低估。
4.3 网络与存储采集路径
网络和存储的采集复杂度高于 CPU/内存,因为涉及多接口、多驱动和持久卷映射。
4.3.1 网络采集:接口级与 Pod 级
- cAdvisor 暴露:
container_network_receive_bytes_total和container_network_transmit_bytes_total,按网络接口(eth0, lo)区分。 - Pod 级聚合:PromQL 使用
sum by (pod, namespace) (rate(container_network_receive_bytes_total{interface="eth0"}[5m]))。 - 成本分摊:通常只统计 eth0 流量,忽略 lo。按入站/出站分别计价。
故障排查要点:如果 Pod 使用
hostNetwork 模式,cAdvisor 无法准确区分容器网络流量,此时网络成本分摊会失效。建议对 hostNetwork Pod 单独使用节点级网络指标或固定费率。
4.3.2 存储采集:临时存储与持久卷
| 存储类型 | 采集方式 | Prometheus 指标 | 注意事项 |
|---|---|---|---|
| 临时存储 (emptyDir) | cAdvisor 读取 cgroup blkio 或 filesystem 统计 | container_fs_usage_bytes |
仅统计容器可写层,不包含镜像层 |
| 持久卷 (PV/PVC) | kubelet 卷指标或 CSI 驱动暴露 | kubelet_volume_stats_used_bytes |
需要 CSI 指标暴露,cAdvisor 不直接采集 |
| 镜像层存储 | 节点级磁盘使用统计 | node_filesystem_avail_bytes |
通常按节点均摊,不按容器分摊 |
4.4 采集链路故障排查清单
当成本分摊数据出现异常时,按以下链路逐层排查,可快速定位故障层。
- 检查 cAdvisor 端点:
curl http://<node-ip>:10250/metrics/cadvisor | head -50,确认容器指标是否正常暴露。 - 验证 Metrics Server:
kubectl top pod -n <namespace>,确认 Pod 级资源指标是否可用。 - 检查 Prometheus 目标状态:在 Prometheus UI 的 Targets 页面确认 kubelet 和 cadvisor 目标为 UP 状态。
- 验证指标存在性:在 Prometheus 中查询
container_cpu_usage_seconds_total{container!="POD"},确认有数据返回。 - 检查标签完整性:确认指标包含
container、pod、namespace标签,且无空值。 - 验证成本计算 PromQL:在 Prometheus 中直接执行成本分摊 PromQL,确认计算结果合理。
快速诊断命令:
# 检查 cAdvisor 指标是否包含目标容器
curl -sk https://node-ip:10250/metrics/cadvisor | grep "container_cpu_usage_seconds_total{container=\"my-app\"}"
# 检查 Metrics Server 聚合延迟
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods/my-app | jq .
4.5 精度与性能权衡
采集间隔、保留周期和指标粒度直接影响成本分摊的精度和存储开销。以下为推荐配置:
| 参数 | 推荐值 | 精度影响 | 存储影响 |
|---|---|---|---|
| Prometheus 采集间隔 | 15s~30s | 间隔越小,CPU 峰值捕捉越准 | 间隔减半,存储翻倍 |
| 指标保留周期 | 30 天(原始) + 90 天(聚合) | 保留越长,历史回溯越完整 | 线性增长,建议配置 TSDB 保留策略 |
| 容器级 vs Pod 级 | 容器级(成本分摊) | 容器级可区分 sidecar 与主容器 | 容器级指标量约为 Pod 级的 2~5 倍 |
| 网络指标接口过滤 | 仅保留 eth0 | 排除 lo 流量,避免成本虚高 | 减少约 30% 的指标基数 |
注意:如果集群规模超过 500 节点,建议使用 Prometheus 分片或 Thanos 架构,避免单点 Prometheus 成为采集瓶颈。同时,cAdvisor 指标基数随容器数量线性增长,需提前规划指标数量上限。