如何处理Prometheus时序空值?实现Helm Chart部署告警
问题背景
我们需要编写PromQL查询,在K8s集群每次部署新Helm Chart版本时返回true,以此触发告警。目前已采集Kube metrics及helm.sh/chart标签,可在Prometheus中查看Chart发布状态。
最初尝试用以下查询统计各Chart的部署实例数,并通过increase检测增长:
increase(sum by (label_helm_sh_chart) (kube_deployment_labels)[1m:])
但遇到问题:当部署新版本Chart(比如把rideshur-web-0.4.1替换为rideshur-web-0.4.2)时,新版本的时序初始为null,首次部署后变为实际计数,increase和change函数无法识别这种null到数值的变化,导致告警未触发。
我们的核心需求:
- 用PromQL识别
null到非null的时序变化 - 为时序中的
null值设置默认值0
另外,网上常见的or on() vector(0)方案不适用,因为我们使用通配符kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}查询时,旧版本时序减少的同时新版本时序已存在,查询结果始终有值,无法补全单个版本的null。
解决方案
核心思路
先为每个匹配的label_helm_sh_chart标签补全历史0值,确保时序从0开始而非null,再通过increase或delta检测从0到非0的变化,以此识别新版本的首次部署。
具体PromQL查询
第一步:补全时序的0值基础查询
sum by (label_helm_sh_chart) (kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}) or on(label_helm_sh_chart) group_left() sum by (label_helm_sh_chart) (kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}) * 0
这个查询会为每个label_helm_sh_chart生成连续的数值:如果该版本已部署则显示实际计数,否则显示0,避免了null的出现。
第二步:检测新版本部署的告警查询
基于补0后的时序,用increase检测增长:
increase( (sum by (label_helm_sh_chart) (kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}) or on(label_helm_sh_chart) group_left() sum by (label_helm_sh_chart) (kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}) * 0 )[1m:] ) > 0
或者用delta直接检测数值变化(更适合这种从0到非0的场景):
delta( (sum by (label_helm_sh_chart) (kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}) or on(label_helm_sh_chart) group_left() sum by (label_helm_sh_chart) (kube_deployment_labels{label_helm_sh_chart=~"rideshur-web-.*"}) * 0 )[1m:] ) > 0
关键逻辑解释
sum by (label_helm_sh_chart) (...) * 0:生成当前所有匹配的label_helm_sh_chart标签对应的0值时序,确保新版本Chart首次出现时,历史窗口内的旧值为0而非nullor on(label_helm_sh_chart) group_left():将原始计数结果与补0时序合并,保证每个Chart版本的时序连续性increase/delta:此时能准确识别从0到非0的变化,也就是新版本Chart的首次部署,返回true触发告警
内容的提问来源于stack exchange,提问作者Lawrence Warren

