十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OneUptime Kubernetes Cost Observability:一条 Helm 命令实现集群成本分摊、Right-Sizing 与成本告警

OneUptime Kubernetes Cost Observability:一条 Helm 命令实现集群成本分摊、Right-Sizing 与成本告警 OneUptime Kubernetes Cost Observability一条 Helm 命令实现集群成本分摊、Right-Sizing 与成本告警【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime本文基于 OneUptime 官方文档 Kubernetes Cost Observability 展开介绍如何用一条helm upgrade命令为 Kubernetes 集群开启成本可观测性Chart 内建 OpenCost 计价引擎与一个最小化 Prometheus按小时窗口把逐工作负载的成本分摊CPU / 内存 / GPU / 持久卷 / 网络 / 负载均衡 / 空闲投递到 OneUptime 的 ClickHouse并在此之上提供成本页面、Right-Sizing 建议与成本指标告警。读完本文你将掌握完整的启用步骤、全部关键配置项的默认值与含义、外部成本引擎的对接方式以及成本数据在仓库中的存储结构与排障手段。快速上手一条命令开启成本观测OneUptime 的 Kubernetes Agent 以 Helm Chart 形式分发。开启成本观测只需要在既有安装上加一个开关helm upgrade oneuptime-agent oneuptime/kubernetes-agent \ --namespace oneuptime-agent \ --reuse-values \ --set cost.enabledtrue这就是完整安装。Chart 捆绑了开源 OpenCost 计价引擎Apache-2.0CNCF 项目即同样驱动 Kubecost 的 cost-model以及它运行所必需的一个最小化、专用 Prometheus——两个小 Pod属于看不见的管道。OpenCost 会自动从云厂商的公开列表价对节点、云盘和负载均衡器计价无需任何云凭证支持 AWS、GCP、Azure本地集群则改为配置一张费率卡见下文本地/裸金属计价。大约在第一个完整的小时窗口闭合后约 1 小时你会得到每集群一个 Costs 页面Kubernetes → 你的集群 → Costs支出趋势、按 namespace 拆分的支出含 CPU/内存/存储拆分、按工作负载的支出、空闲支出与请求-使用效率项目级 Costs 页面Kubernetes → Costs跨项目内所有集群的支出汇总Kubernetes Cost 仪表盘模板Dashboards → Create → Kubernetes Cost Dashboard节点每小时成本趋势、CPU/内存单价、持久卷与负载均衡器支出原始成本指标node_total_hourly_cost、pv_hourly_cost等进入Metric Explorer可用于自定义仪表盘和指标告警。Agent 与成本观测能力的对应关系也可以参考同目录的 Kubernetes Agent 文档。架构解析cost.enabledtrue时 Chart 实际启动了什么开启后Chart 运行四个组件。默认值与资源规格定义在 values.yaml 的cost:段部署模板分别位于 opencost.yaml、prometheus-cost.yaml 和 deployment-cost-agent.yaml。1. 内建 OpenCost 计价引擎OpenCost捆绑负责监听集群、发现云列表价、计算逐工作负载的预计价成本分摊。Chart 默认使用ghcr.io/opencost/opencost:1.121.0镜像资源规格为 requests50m/128Mi、limits500m/1Gi。它自己会发出 KSM 风格的 resource-request 指标——这正是后面 Prometheus 不需要部署 kube-state-metrics 的原因。2. 最小化专用 PrometheusOpenCost 硬性要求一个 PromQL 端点来重建用量/价格历史。这个 Prometheus只为它服务单副本、默认 7 天保留、恰好两个抓取目标且永不暴露到集群外数据也永不离开集群。从 prometheus-cost.yaml 可以看到其完整配置global: scrape_interval: 60s # 默认值来自 cost.prometheus.scrapeInterval evaluation_interval: 60s scrape_configs: - job_name: kubernetes-nodes-cadvisor # 通过 API-server node proxy 抓取每个节点的 cAdvisor # 无需 hostNetwork/hostPortGKE Autopilot 兼容 # 复用 agent ServiceAccount 既有的 nodes/proxy RBAC scheme: https kubernetes_sd_configs: - role: node relabel_configs: - target_label: __address__ replacement: kubernetes.default.svc:443 - source_labels: [__meta_kubernetes_node_name] target_label: __metrics_path__ replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor - job_name: opencost # OpenCost 自身指标节点/云盘小时单价、逐容器分摊、 # 以及它自产的 KSM 风格 resource-request 序列 honor_labels: true模板层面还做了两点值得注意的约束数据卷默认是emptyDirPod 重启会丢几小时历史开启cost.prometheus.persistence.enabled时切换为 PVC 并把部署策略改为RecreateRWO 卷不能同时挂两个 Pod因此禁止 surge容器以runAsNonRootUID 65534、只读根文件系统运行。默认镜像为quay.io/prometheus/prometheus:v2.55.1。3. 成本分摊轮询器cost agent这是 KubernetesCostAgent 目录实现的独立小服务Chart 中的oneuptime/kubernetes-cost-agent镜像。其轮询逻辑核心在 Poller.ts窗口机制每POLL_INTERVAL_SECONDS默认 300s检查是否有新的WINDOW_SECONDS默认 3600s即 1 小时窗口已闭合且稳定——窗口闭合后还要等ENGINE_SETTLE_SECONDS默认 120s让引擎完成计价与对账见 Poller.ts 的 tick 循环。严格顺序 检查点窗口严格按顺序发送检查点只有在整个窗口成功落地后才推进失败的窗口在下个 tick 重试。检查点只存在于内存中——重启后 Agent 会重发最近LOOKBACK_WINDOWS默认 2个已闭合窗口而服务端会跳过已有行的窗口因此重启不可能造成重复计费。这一点在 Poller.ts 构造函数 和 KubernetesCostAllocation 模型的 shipmentId 字段说明 中有明确注释。健康检查的读写分离/healthz是就绪探针一旦确实坏了连续HEALTH_MAX_POLL_FAILURES次轮询失败、HEALTH_STALE_WINDOWS个窗口无进展、或明显早该发出却没发过任何数据即返回503 degraded让 Pod 显示0/1 Ready而不是绿灯空转/livez只反映进程存活——重启修不好宕机的成本引擎重启循环反而会丢掉内存中的检查点和诊断信息。单独的沉默永远不会使 Agent 判死因为健康的成本 Agent 大部分时间本来就是空闲的。环境变量完整清单含默认值见 KubernetesCostAgent/README.md核心项变量默认值说明ONEUPTIME_URL/ONEUPTIME_API_KEY必填OneUptime 主机地址与遥测摄取密钥CLUSTER_NAME必填必须与指标 Agent 打的k8s.cluster.name一致COST_ENGINE_URL必填引擎基址如http://opencost.opencost.svc.cluster.local:9003COST_ALLOCATION_PATH自动探测显式指定 Allocation API 路径WINDOW_SECONDS3600分摊窗口长度POLL_INTERVAL_SECONDS300轮询间隔ENGINE_SETTLE_SECONDS120窗口闭合后的等待时间LOOKBACK_WINDOWS2启动时重发的已闭合窗口数INCLUDE_IDLEtrue是否投递__idle__分摊SHIP_BATCH_SIZE1000每批行数服务端上限 50004. 成本指标抓取cost.metricsAgent 的 OpenTelemetry Collector 顺带抓取 OpenCost 的 Prometheus 指标走与集群其他指标相同的 OTLP 管道。默认开启cost.metrics.enabled: truescrapeInterval: 60s并带有一份精确匹配的白名单因为引擎导出的序列远不止这些逐容器的 allocation 序列会把基数放大到容器数量级。默认白名单values.yamlmetricsAllowlist: - node_cpu_hourly_cost - node_gpu_hourly_cost - node_ram_hourly_cost - node_total_hourly_cost - container_cpu_allocation - container_gpu_allocation - container_memory_allocation_bytes - pod_pvc_allocation - pv_hourly_cost - kubecost_cluster_management_cost - kubecost_load_balancer_cost - kubecost_network_zone_egress_cost - kubecost_network_region_egress_cost - kubecost_network_internet_egress_cost已有 Kubecost 或 OpenCost直接指向现有引擎如果你的集群已在跑 Kubecost 或 OpenCost不必再部署捆绑组件让 Chart 直接读你的引擎helm upgrade oneuptime-agent oneuptime/kubernetes-agent \ --namespace oneuptime-agent \ --reuse-values \ --set cost.enabledtrue \ --set cost.engine.urlhttp://kubecost-cost-analyzer.kubecost.svc.cluster.local:9090引擎典型 Service URLOpenCosthttp://opencost.opencost.svc.cluster.local:9003Kubecosthttp://kubecost-cost-analyzer.kubecost.svc.cluster.local:9090Allocation API 路径是自动探测的探测顺序为/model/allocationKubecost→/allocation/computeOpenCost→/allocation旧版 OpenCost。只有非标准安装才需要显式设置cost.engine.allocationPath。一旦设置了cost.engine.urlChart 就不再部署捆绑的 OpenCost 和 Prometheus模板里通过kubernetes-agent.costEngineBundled判定此时若想保留内存 Right-Sizing 能力需要另外指定cost.engine.prometheusUrl见下文。本地 / 裸金属计价自定义费率卡节点没有公有云列表价的集群本地、裸金属、气隙环境可以配置费率卡——OpenCost 随后按这些数字给一切资源计价。所有值单位均为USD / 资源-小时cost: enabled: true opencost: customPricing: enabled: true cpuPerCoreHour: 0.031611 # ~$23 每核-月 ramPerGiBHour: 0.004237 # ~$3 每 GiB-月 storagePerGBHour: 0.00005479452 # ~$0.04 每 GB-月 gpuPerHour: 0.95Chart 中该节实际上还有更多可调项完整默认值见 values.yaml默认值源自 cost-model 的 GCP-us-central1 推导值opencost: customPricing: enabled: false cpuPerCoreHour: 0.031611 spotCpuPerCoreHour: 0.006655 ramPerGiBHour: 0.004237 spotRamPerGiBHour: 0.000892 gpuPerHour: 0.95 storagePerGBHour: 0.00005479452 zoneNetworkEgressPerGB: 0.01 regionNetworkEgressPerGB: 0.01 internetNetworkEgressPerGB: 0.12按需补充抢占实例spot单价与网络出流量单价即可enabled: false时保持云厂商列表价自动计价。常用配置项汇总cost:段下所有键均为可选完整清单以 Chart 的 values.yaml 为准。以下是文档与源码中的关键项及其默认值cost: enabled: false engine: url: # 非空则使用外部引擎不部署任何捆绑组件 allocationPath: # 留空则按 /model/allocation → /allocation/compute → /allocation 探测 prometheusUrl: # 外部引擎下读内存峰值用的 Prometheus 地址 prometheusCadvisorJob: # 外部 Prometheus 的 cAdvisor 抓取 job 名默认假设 kubernetes-nodes-cadvisor opencost: image: { repository: ghcr.io/opencost/opencost, tag: 1.121.0 } logLevel: info resources: { requests: { cpu: 50m, memory: 128Mi }, limits: { cpu: 500m, memory: 1Gi } } customPricing: { enabled: false, ... } prometheus: image: { repository: quay.io/prometheus/prometheus, tag: v2.55.1 } retention: 7d # 捆绑 TSDB 保留期Right-Sizing 会跨多天回溯读取峰值 scrapeInterval: 60s resources: { requests: { cpu: 50m, memory: 256Mi }, limits: { cpu: 500m, memory: 1Gi } } persistence: enabled: false # true 时挂一个小 PVC默认 10Gi否则用 emptyDir size: 10Gi agent: enabled: true windowSeconds: 3600 # 分摊窗口长度小时级 引擎原生精度 pollIntervalSeconds: 300 # 检查新闭合窗口的频率 engineSettleSeconds: 120 # 窗口闭合后等引擎计价/对账完成 lookbackWindows: 2 # 启动时重发的已闭合窗口数服务端去重不会双计 includeIdle: true # 投递引擎的 __idle__ 分摊 currency: USD # 随每个 payload 转发的币种码UI 展示用 logLevel: info resources: { requests: { cpu: 50m, memory: 64Mi }, limits: { cpu: 200m, memory: 256Mi } } metrics: enabled: true # 成本指标进入 Metric Explorer / 仪表盘 endpoint: # 留空默认为 cost.engine.url/metrics scrapeInterval: 60s metricsAllowlist: [ ... ] # 见上文精确匹配白名单两个值得说明的默认值理由retention: 7d仅看支出几天历史就够轮询器只查最近闭合的窗口之所以给到 7 天是因为 Right-Sizing 需要跨多天回溯读内存峰值——超出保留期的窗口查不到峰值该天的证据会静默丢失。windowSeconds: 3600小时级是引擎原生 ETL 精度更长丢粒度更短则会被引擎插值没有意义。Right-Sizing基于真实使用数据的请求值建议集群 Costs 页面上的Right-Sizing卡片会为历史足够充分的每个容器给出 CPU 与内存 request 建议并按每项调整每月能省多少钱排序。其算法是一个纯计算模块独立于前端、可单测复用实现在 KubernetesRightSizing.ts配套测试在 KubernetesRightSizing.test.ts。一条设计不对称性驱动了整个算法CPU request 设低了只是限流内存 request 设低了会 OOMKill——所以 CPU 用小时均值的 P95 定容内存只用真实峰值定容。建议值如何算出建议值 观测需求 25% 余量CPU_HEADROOM_RATIO/MEMORY_HEADROOM_RATIO均为 0.25再取整到可以直接粘进 manifest 的刻度CPU 到 10m0.01 核、内存到 16Mi同时有地板值兜底CPU 不低于 0.01 核、内存不低于 32Mi避免建议出调度不良、看起来像噪声的值CPU按小时平均用量的P95定容足以覆盖真实负载又不会让一次尖峰把 request 抬高一个月内存按峰值工作集定容——绝不用平均值理由见下文数据背后的来源。只推荐 request不推荐 limitrequest 是调度器预留、也是账单计算所依据的数值是真正影响成本的那个数limit 是你宁可被限流还是被杀掉的爆炸半径决策使用数据替你做不了这个决定。四个判定与两条护栏每个容器对照其当前 request 打分RightSizingVerdict 枚举Overprovisioned超配——预留远超实际使用节省估计就来自这里Underprovisioned欠配——预留低于实际使用正在被限流或有 OOMKill 风险。修复它要花钱卡片把这笔钱显示为增量而不是藏起来NoRequestSet未设 request——无可缩减空间但调度器无法安全放置该容器资源紧张时它第一个被驱逐与建议值相差15% 以内SIGNIFICANCE_RATIO视为已合理Optimal直接略过——没人应该为省 3% 去改 manifest。两条护栏保证建议诚实最少 24 小时观测MIN_OBSERVED_HOURS/MIN_SAMPLE_COUNT 244 小时的窗口可能恰好逮到夜间批处理任务在休息会一本正经地建议你把它缩到零节省按窗口时长外推而非按行数一个 Deployment 的节省不会因为副本数多而被乘以副本数月投影用HOURS_IN_MONTH 730折算。节省估计假设支出现在引擎的分摊口径上即max(request, usage)。对超配场景它退化为 request 本身——所以省下的数字是精确值而非近似值。数据背后的来源为什么内存要另查 Prometheus轮询器随支出数据一起收集 Right-Sizing 所需的每个容器的 CPU/内存request、limit和usage。内存还需要一个额外数据源Allocation API 只报告窗口内的平均值而小时均值会掩盖那个导致 OOMKill 的突发——用均值定内存 request 是主动危险的做法。因此 Agent 从 Prometheus 读每个容器的内存峰值按(namespace, pod, container)关联。这一列落在 KubernetesCostAllocation 模型的ramBytesUsageMax上列注释明确写着0 应理解为未知绝不是真实的零峰值。该能力是可选的、可干净降级的内建引擎默认自动使用 Chart 自带的 Prometheus无需任何配置外部引擎设置了cost.engine.url没有捆绑 Prometheus需指向一个抓取了 cAdvisor 的 Prometheus 设cost.engine.prometheusUrl若其抓取 job 不叫kubernetes-nodes-cadvisor再设cost.engine.prometheusCadvisorJob完全没有 PrometheusCPU 建议照常工作由存储的小时均值推导内存建议不可用而不是给错值。Prometheus 故障永远不会阻塞支出采集峰值只是增强项窗口照常发出Poller.ts 中对峰值采集的独立 try/catch 保证峰值路径的任何异常都不会卡住检查点。而 CPU 则刻意不用Prometheus超 CPU request 只是限流、超内存才会杀容器所以用 ClickHouse 里已有的小时均值安全定容同时全集群逐容器 CPU rate 查询开销大足以压垮一个小 Prometheus。基于成本指标做告警抓取进来的成本指标就是普通的 OneUptime 指标可以像其他指标一样配告警——例如平均node_total_hourly_cost超过预算阈值时告警或某集群中出现了本不该存在的存储类对应的pv_hourly_cost时告警。数据模型与保留策略分摊行存入 ClickHouse 表KubernetesCostAllocation模型定义在 KubernetesCostAllocation.ts每行对应 (集群, 窗口, namespace, controller, pod, container) 一个切片含预计价成本分量与效率比率。关键字段分组维度clusterName、namespace、controllerKind/controllerName、podName/containerName、nodeName、providerId、labelsMap支持按标签做成本归组如 team/app/env用量与成本cpuCoreHours、cpuCost、gpuHours/gpuCost、ramByteHours/ramCost、pvByteHours/pvCost、networkCost、loadBalancerCost、sharedCost集群固定开销分摊、externalCost、totalCost以及 request/usage/limit 均值cpuCoreRequestAverage、ramBytesRequestAverage等效率cpuEfficiency、ramEfficiencyusage/request 比、totalEfficiency成本加权交付簿记shipmentIdAgent 对窗口的内容哈希跨重启一致与shipmentChunk用于区分同一交付的另一个分片接受与此前已摄入的窗口丢弃。两个设计要点空闲与未分配容量是普通行其namespace为引擎哨兵值__idle__/__unallocated__——因此空闲支出可以与工作负载支出用同样的 GROUP BY 查询保留策略跟随集群遥测保留期行上带retentionDate摄入时按windowStart 集群资源上的retainTelemetryDataForDays计算缺省回落到项目保留期表设置ttlExpression: retentionDate DELETE。表按toYYYYMMDD(windowStart)分区、按cityHash64(projectId, kubernetesClusterId)分片使单个集群的成本行尽量同置——因为所有查询要么过滤单集群、要么扇出到项目内全部集群。排障手册文档给出的完整排障清单覆盖绝大多数场景Costs 页面为空——看成本 Agent 日志kubectl logs -n agent namespace deploy/release-kubernetes-agent-cost。401说明摄取密钥无效cost engine did not answer any known allocation path说明引擎还没起来捆绑 OpenCost 安装后需要几分钟才能给第一个窗口计价或cost.engine.url写错。另外Agent 的/healthz在管道确实停摆时会转503 degraded见上文健康检查设计Pod 会显示0/1 Ready而不是空转绿灯。捆绑 OpenCost 未就绪——kubectl logs -n agent namespace deploy/release-kubernetes-agent-opencost日志会打印它检测到的云厂商以及计价数据是否加载成功。OpenCost 日志出现mkdir /var/configs: permission denied——这是 chart 0.6.1 已修复的 bugOpenCost 以非 root 运行但配置目录不可写导致Error downloading default pricing dataAllocation API 无法应答、轮询器卡住——而 Pod 保持Running、/healthz保持绿灯、节点成本指标仍在发布。修复方式是升级 Charthelm repo update helm upgrade ... --reuse-values下一轮轮询即出现成本行。仪表盘模板无数据——模板读的是抓取来的成本指标确认cost.metrics.enabled为true。Right-Sizing 卡片为空——要么时间范围短于建议所需的 24 小时拉宽时间范围要么所有容器都已在建议值 15% 以内卡片会明确说明这一点。内存建议显示-但 CPU 建议正常——内存峰值没有到达服务端内存被刻意留空而非按均值猜测。外部引擎安装请设置cost.engine.prometheusUrl卡片会报告受影响的容器数。与引擎自身 UI 的数字对不上——OneUptime 包含引擎在每个成本分量中的对账reconciliation调整且发送的是完整闭合窗口当前小时的部分支出要等窗口闭合后才会出现。Prometheus Pod 重启后——默认emptyDir存储下重启会丢几小时用量历史这些窗口的分摊值可能偏小。介意的话设cost.prometheus.persistence.enabledtrue。小结OneUptime 的 Kubernetes 成本观测把集群花了多少钱、花在哪里、怎么省做成了遥测流水线的一部分一条--set cost.enabledtrue完成安装内建 OpenCost 最小 Prometheus 负责计价与历史专用轮询器以小时窗口、严格顺序、服务端去重的方式把分摊行送进 ClickHouseRight-Sizing 模块在CPU 用 P95、内存用峰值的不对称原则下给出可直接落进 manifest 的 request 建议成本指标则复用既有的告警与 Metric Explorer 体系。全部组件的默认值、资源规格与白名单都收敛在 values.yaml 的 cost 段可作为线上调优的唯一权威参照。【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表