转载自:https://www.qikqiak.com/post/prometheus-monitor-k8s-job-trap/

昨天在 Prometheus 课程辅导群里面有同学提到一个问题,是关于 Prometheus 监控 Job 任务误报的问题,大概的意思就 CronJob 控制的 Job,前面执行失败了,监控会触发报警,解决后后面生成的新的 Job 可以正常执行了,但是还是会收到前面的报警:


  1. 这是因为一般在执行 Job 任务的时候我们会保留一些历史记录方便排查问题,所以如果之前有失败的 Job 了,即便稍后会变成成功的,那么之前的 Job 也会继续存在,而大部分直接使用 kube-prometheus 安装部署的话使用的默认报警规则是kube_job_status_failed > 0,这显然是不准确的,只有我们去手动删除之前这个失败的 Job 任务才可以消除误报,当然这种方式是可以解决问题的,但是不够自动化,一开始没有想得很深入,想去自动化删除失败的 Job 来解决,但是这也会给运维人员带来问题,就是不方便回头去排查问题。下面我们来重新整理下思路解决下这个问题。
  2. CronJob 会在计划的每个执行时间创建一个 Job 对象,可以通过 .spec.successfulJobsHistoryLimit .spec.failedJobsHistoryLimit 属性来保留多少已完成和失败的 Job,默认分别为31,比如下面声明一个 CronJob 的资源对象:
  3. apiVersion: batch/v1
  4. kind: CronJob
  5. metadata:
  6. name: hello
  7. spec:
  8. schedule: "*/1 * * * *"
  9. successfulJobsHistoryLimit: 1
  10. failedJobsHistoryLimit: 1
  11. jobTemplate:
  12. spec:
  13. template:
  14. spec:
  15. containers:
  16. - name: hello
  17. image: busybox
  18. imagePullPolicy: IfNotPresent
  19. command:
  20. - /bin/sh
  21. - -c
  22. - date;
  23. restartPolicy: OnFailure
  24. 根据上面的资源对象规范,Kubernetes 将只保留一个失败的 Job 和一个成功的 Job
  25. NAME COMPLETIONS DURATION AGE
  26. hello-4111706356 0/1 2m 10d
  27. hello-4111706356 1/1 5s 5s
  28. 要解决上面的误报问题,同样还是需要使用到 kube-state-metrics 这个服务,它通过监听 Kubernetes APIServer 并生成有关对象状态的指标,它并不关注单个 Kubernetes 组件的健康状况,而是关注内部各种对象的健康状况,例如 DeploymentNodeJobPod 等资源对象的状态。这里我们将要使用到以下几个指标:
  29. kube_job_owner:用来查找 Job 和触发它的 CronJob 之间的关系
  30. kube_job_status_start_time:获取 Job 被触发的时间
  31. kube_job_status_failed:获取执行失败的任务
  32. kube_cronjob_spec_suspend:过滤掉挂起的作业
  33. 下面是一个指标示例,其中包含 CronJob 触发运行的hello 任务生成的标签:
  34. kube_job_owner{job_name="hello-1604875860", namespace="myNamespace", owner_is_controller="true", owner_kind="CronJob", owner_name="hello"} 1
  35. kube_job_status_start_time{job_name="hello-1604875860", namespace="myNamespace"} 1604875874
  36. kube_job_status_failed{job_name="hello-1604875860", namespace="myNamespace", reason="BackoffLimitExceeded"} 1
  37. kube_cronjob_spec_suspend{cronjob="hello",job="kube-state-metrics", namespace="myNamespace"} 0
  38. 要想做到监控报警准确,其实我们只需要去获取同一个 CronJob 触发的一组 Job 的最后一次任务,只有该 Job 在执行失败的时候才触发报警即可。 由于 kube_job_status_failed kube_job_status_start_time 指标中并不包含所属 CronJob 的标签,所以第一步需要加入这个标签,而 kube_job_owner 指标中的 owner_name 就是我们需要的,可以用下面的 promql 语句来进行合并:
  39. max(
  40. kube_job_status_start_time
  41. * ON(job_name, namespace) GROUP_RIGHT()
  42. kube_job_owner{owner_name != ""}
  43. )
  44. BY (job_name, owner_name, namespace)
  45. 这里我们使用 max 函数是因为我们可能会因为 HA 运行多个 kube-state-metrics,所以用 max 函数来返回每个 Job 任务的一个结果即可。假设我们的 Job 历史记录包含 2 个任务(一个失败,另一个成功),结果将如下所示:
  46. {job_name="hello-1623578940", namespace="myNamespace", owner_name="hello"} 1623578959
  47. {job_name="hello-1617667200", namespace="myNamespace", owner_name="hello"} 1617667204
  48. 现在我们知道每个 Job 的所有者了,接着我们需要找出最后执行的任务,我们可以通过按 owner_name 标签聚合结果来实现这一点:
  49. max(
  50. kube_job_status_start_time
  51. * ON(job_name,namespace) GROUP_RIGHT()
  52. kube_job_owner{owner_name!=""}
  53. )
  54. BY (owner_name)
  55. 上面这条语句会找到每个 owner(也就是 CronJob)最新的任务开始时间,然后再和上面的语句进行合并,保留开始时间相同的记录即为最新执行的 Job 任务了:
  56. max(
  57. kube_job_status_start_time
  58. * ON(job_name,namespace) GROUP_RIGHT()
  59. kube_job_owner{owner_name!=""}
  60. )
  61. BY (job_name, owner_name, namespace)
  62. == ON(owner_name) GROUP_LEFT()
  63. max(
  64. kube_job_status_start_time
  65. * ON(job_name,namespace) GROUP_RIGHT()
  66. kube_job_owner{owner_name!=""}
  67. )
  68. BY (owner_name)
  69. 结果将显示每个 CronJob 最后执行的作业,并且仅显示最后一个:
  70. {job_name="hello-1623578940", namespace="myNamespace", owner_name="hello"} 1623578959
  71. 为了增加可读性我们还可以将 job_nameowner_name 标签替换为 job cronjob,这样更容易看明白:
  72. label_replace(
  73. label_replace(
  74. max(
  75. kube_job_status_start_time
  76. * ON(job_name,namespace) GROUP_RIGHT()
  77. kube_job_owner{owner_name!=""}
  78. )
  79. BY (job_name, owner_name, namespace)
  80. == ON(owner_name) GROUP_LEFT()
  81. max(
  82. kube_job_status_start_time
  83. * ON(job_name,namespace) GROUP_RIGHT()
  84. kube_job_owner{owner_name!=""}
  85. )
  86. BY (owner_name),
  87. "job", "$1", "job_name", "(.+)"),
  88. "cronjob", "$1", "owner_name", "(.+)")
  89. 现在将会看到类似于下面的结果:
  90. {job="hello-1623578940", cronjob="hello", job_name="hello-1623578940", namespace="myNamespace", owner_name="hello"} 1623578959
  91. 由于上面的查询语句比较复杂,如果每次报警评估的时候都去进行一次实时计算会对 Prometheus 产生非常大的压力,这里我们可以借助记录规则来实现类离线计算的方式,大大提高效率,创建如下所示的记录规则,用来表示获取每个 CronJob 最后执行的作业记录:
  92. - record: job:kube_job_status_start_time:max
  93. expr: |
  94. label_replace(
  95. label_replace(
  96. max(
  97. kube_job_status_start_time
  98. * ON(job_name,namespace) GROUP_RIGHT()
  99. kube_job_owner{owner_name!=""}
  100. )
  101. BY (job_name, owner_name, namespace)
  102. == ON(owner_name) GROUP_LEFT()
  103. max(
  104. kube_job_status_start_time
  105. * ON(job_name,namespace) GROUP_RIGHT()
  106. kube_job_owner{owner_name!=""}
  107. )
  108. BY (owner_name),
  109. "job", "$1", "job_name", "(.+)"),
  110. "cronjob", "$1", "owner_name", "(.+)")
  111. 现在我们知道了 CronJob 最近开始执行的 Job 了,那么想要过滤出失败的,则再使用 kube_job_status_failed 指标就可以了:
  112. - record: job:kube_job_status_failed:sum
  113. expr: |
  114. clamp_max(job:kube_job_status_start_time:max, 1)
  115. * ON(job) GROUP_LEFT()
  116. label_replace(
  117. (kube_job_status_failed > 0),
  118. "job", "$1", "job_name", "(.+)"
  119. )
  120. 这里使用 clamp_max 函数将 job:kube_job_status_start_time:max 的结果转换为一组上限为 1 的时间序列,使用它来通过乘法过滤失败的作业,得到包含一组最近失败的 Job 任务,这里我们也添加到名为 kube_job_status_failed:sum 的记录规则中。
  121. 最后一步就是直接为失败的 Job 任务添加报警规则,如下所示:
  122. - alert: CronJobStatusFailed
  123. expr: |
  124. job:kube_job_status_failed:sum
  125. * ON(cronjob, namespace) GROUP_LEFT()
  126. (kube_cronjob_spec_suspend == 0)
  127. 为避免误报,我们已将挂起的任务排除在外了。到这里我们就解决了 Prometheus 监控 CronJob 的任务误报的问题,虽然 kube-prometheus 为我们内置了大量的监控报警规则,但是也不能完全迷信,有时候并不一定适合实际的需求。

Prometheus 监控 Kubernetes Job 资源误报的坑的更多相关文章

  1. 第15章: Prometheus监控Kubernetes资源与应用

    Prometheus监控Kubernetes资源与应用 目录 1 监控方案 2 2 监控指标 4 3 实现思路 4 4 在K8S中部署Prometheus 4 5 在K8S中部署Grafana与可视化 ...

  2. Kubernetes集群部署史上最详细(二)Prometheus监控Kubernetes集群

    使用Prometheus监控Kubernetes集群 监控方面Grafana采用YUM安装通过服务形式运行,部署在Master上,而Prometheus则通过POD运行,Grafana通过使用Prom ...

  3. Prometheus监控学习笔记之解读prometheus监控kubernetes的配置文件

    0x00 概述 Prometheus 是一个开源和社区驱动的监控&报警&时序数据库的项目.来源于谷歌BorgMon项目.现在最常见的Kubernetes容器管理系统中,通常会搭配Pro ...

  4. 部署prometheus监控kubernetes集群并存储到ceph

    简介 Prometheus 最初是 SoundCloud 构建的开源系统监控和报警工具,是一个独立的开源项目,于2016年加入了 CNCF 基金会,作为继 Kubernetes 之后的第二个托管项目. ...

  5. Kubernetes容器集群管理环境 - Prometheus监控篇

    一.Prometheus介绍之前已经详细介绍了Kubernetes集群部署篇,今天这里重点说下Kubernetes监控方案-Prometheus+Grafana.Prometheus(普罗米修斯)是一 ...

  6. 监控 -- kubernetes -- prometheus

    1.但是Heapster无法做Kubernetes下应用的监控.现在,Heapster作为Kubernetes下的开源监控解决方案已经被其弃用,Prometheus成为Kubernetes官方推荐的监 ...

  7. Kubernetes学习之路(二十四)之Prometheus监控

    目录 1.Prometheus概述 2.Prometheus部署 2.1.创建名称空间prom 2.2.部署node_exporter 2.3.部署prometheus-server 2.4.部署ku ...

  8. [转帖]Prometheus+Grafana监控Kubernetes

    原博客的位置: https://blog.csdn.net/shenhonglei1234/article/details/80503353 感谢原作者 这里记录一下自己试验过程中遇到的问题: . 自 ...

  9. Prometheus Operator 监控Kubernetes

    Prometheus Operator 监控Kubernetes 1. Prometheus的基本架构 ​ Prometheus是一个开源的完整监控解决方案,涵盖数据采集.查询.告警.展示整个监控流程 ...

随机推荐

  1. DNS 系列(一):为什么更新了 DNS 记录不生效?

    我们在上网时如果想要访问到另一台机器上的内容,通常只需要直接输入一串地址,例如:www.upyun.com,就能够准确访问到自己想要访问的网站.但是实际上这只是方便我们记忆的字符形式网络标识,真正让我 ...

  2. Tapdata Real Time DaaS 技术详解 PART I :实时数据同步

      摘要:企业信息化过程形成了大量的数据孤岛,这些并不连通的数据孤岛是企业数字化转型的巨大挑战.Tapdata Real Time DaaS 采用的CDC模式,具有巨大的优势,同时是一个有技术壁垒的活 ...

  3. SpringCloud Gateway微服务网关实战与源码分析-上

    概述 定义 Spring Cloud Gateway 官网地址 https://spring.io/projects/spring-cloud-gateway/ 最新版本3.1.3 Spring Cl ...

  4. 优化对称加密的 shell 脚本

    前言 之前一篇文章<shell 脚本实现文件对称加密>中,讲述了如何用 shell 脚本实现对称加密. 之后写管理密码脚本时,发觉该脚本的处理速度非常慢,而其原因就在 shell 的处理命 ...

  5. 【Python爬虫技巧】快速格式化请求头Request Headers

    你好,我是 @马哥python说 . 我们在写爬虫时,经常遇到这种问题,从目标网站把请求头复制下来,粘贴到爬虫代码里,需要一点一点修改格式,因为复制的是字符串string格式,请求头需要用字典dict ...

  6. 应用启动加速-并发初始化spring bean

    背景 随着需求的不断迭代,服务承载的内容越来越多,依赖越来越多,导致服务启动慢,从最开始的2min以内增长到5min,导致服务发布很慢,严重影响开发效率,以及线上问题的修复速度.所以需要进行启动加速. ...

  7. 作业一、安装Ubuntu系统

    Ubuntu1804安装 一.安装环境 1.VMware Workstation 16 Pro 2.Ubuntu 18.04.6 LTS 二.部署系统 步骤1.进入VMware,点击创建新的虚拟机 步 ...

  8. “杀死” App 上的疑难崩溃

    在移动应用性能方面,崩溃带来的影响是最为严重的,程序崩了可以打断用户正在进行的操作体验,造成关键业务中断.用户留存率下降.品牌口碑变差.生命周期价值下降等影响.很多公司将崩溃率作为优先级最高的技术指标 ...

  9. python代码如何写的优雅?

    简介 在实际项目中,我们可能一开始为了完成功能而忽视了代码的整体质量,因此,使用一些高阶的函数或方法,能够更加使我们的代码更加优雅.废话不多说,现在马上开始. 使用enumerate方法替代range ...

  10. PySpark 大数据处理

    本文主要介绍Spark的一些基本算子,PySpark及Spark SQL 的使用方法. 虽然我从2014年就开始接触Spark,但几年来一直没有真正地学以致用,时间一久便忘了如何使用,直到在工作中用到 ...