亚洲一区精品自拍_2021年国内精品久久_男同十八禁gv在线观看_免费观看a级性爱黄片

當(dāng)前位置:文章中心>技術(shù)教程
公告通知 新聞快遞 技術(shù)教程 產(chǎn)品展示

解決 Prometheus 監(jiān)控 Kubernetes Job 誤報(bào)的坑

發(fā)布時(shí)間:2022-03-07 點(diǎn)擊數(shù):1030

編輯搜圖

昨天在 Prometheus 課程輔導(dǎo)群里面有同學(xué)提到一個(gè)問(wèn)題,是關(guān)于 Prometheus 監(jiān)控 Job 任務(wù)誤報(bào)的問(wèn)題(已經(jīng)同步到社區(qū)網(wǎng)站),大概的意思就 CronJob 控制的 Job,前面執(zhí)行失敗了會(huì)觸發(fā)報(bào)警,后面生成的新的 Job 可以正常執(zhí)行后,但是還是會(huì)收到前面的報(bào)警:

編輯搜圖

這是因?yàn)橐话阍趫?zhí)行 Job 任務(wù)的時(shí)候我們會(huì)保留一些歷史記錄方便排查問(wèn)題,所以如果之前有失敗的 Job 了,即便稍后會(huì)變成成功的,那么之前的 Job 也會(huì)繼續(xù)存在,而大部分直接使用 kube-prometheus 安裝部署的話使用的默認(rèn)報(bào)警規(guī)則是kube_job_status_failed > 0,這顯然是不準(zhǔn)確的,只有我們?nèi)ナ謩?dòng)刪除之前這個(gè)失敗的 Job 任務(wù)才可以消除誤報(bào),當(dāng)然這種方式是可以解決問(wèn)題的,但是不夠自動(dòng)化,一開(kāi)始沒(méi)有想得很深入,想去自動(dòng)化刪除失敗的 Job 來(lái)解決,但是這也會(huì)給運(yùn)維人員帶來(lái)問(wèn)題,就是不方便回頭去排查問(wèn)題。下面我們來(lái)重新整理下思路解決下這個(gè)問(wèn)題。

CronJob 會(huì)在計(jì)劃的每個(gè)執(zhí)行時(shí)間創(chuàng)建一個(gè) Job 對(duì)象,可以通過(guò) .spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit 屬性來(lái)保留多少已完成和失敗的 Job,默認(rèn)分別為3和1,比如下面聲明一個(gè) CronJob 的資源對(duì)象:

復(fù)制
apiVersion: batch/v1kind: CronJobmetadata:  name: hellospec:  schedule: "*/1 * * * *"
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 1
  jobTemplate:    spec:      template:        spec:          containers:
          - name: hello
            image: busybox
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - date;          restartPolicy: OnFailure1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.

根據(jù)上面的資源對(duì)象規(guī)范,Kubernetes 將只保留一個(gè)失敗的 Job 和一個(gè)成功的 Job:

復(fù)制
NAME               COMPLETIONS   DURATION   AGEhello-4111706356   0/1           2m         10dhello-4111706356   1/1           5s         5s1.2.3.

要解決上面的誤報(bào)問(wèn)題,同樣還是需要使用到 kube-state-metrics 這個(gè)服務(wù),它通過(guò)監(jiān)聽(tīng) Kubernetes APIServer 并生成有關(guān)對(duì)象狀態(tài)的指標(biāo),它并不關(guān)注單個(gè) Kubernetes 組件的健康狀況,而是關(guān)注內(nèi)部各種對(duì)象的健康狀況,例如 Deployment、Node、Job、Pod 等資源對(duì)象的狀態(tài)。這里我們將要使用到以下幾個(gè)指標(biāo):

  • kube_job_owner:用來(lái)查找 Job 和觸發(fā)它的 CronJob 之間的關(guān)系。

  • kube_job_status_start_time:獲取 Job 被觸發(fā)的時(shí)間。

  • kube_job_status_failed:獲取執(zhí)行失敗的任務(wù)。

  • kube_cronjob_spec_suspend:過(guò)濾掉掛起的作業(yè)。

下面是一個(gè)指標(biāo)示例,其中包含 CronJob 觸發(fā)運(yùn)行的hello 任務(wù)生成的標(biāo)簽:

復(fù)制
kube_job_owner{job_name="hello-1604875860", namespace="myNamespace", owner_is_controller="true", owner_kind="CronJob", owner_name="hello"} 1kube_job_status_start_time{job_name="hello-1604875860", namespace="myNamespace"} 1604875874kube_job_status_failed{job_name="hello-1604875860", namespace="myNamespace", reason="BackoffLimitExceeded"} 1kube_cronjob_spec_suspend{cronjob="hello",job="kube-state-metrics", namespace="myNamespace"} 01.2.3.4.

要想做到監(jiān)控報(bào)警準(zhǔn)確,其實(shí)我們只需要去獲取同一個(gè) CronJob 觸發(fā)的一組 Job 的最后一次任務(wù),只有該 Job 在執(zhí)行失敗的時(shí)候才觸發(fā)報(bào)警即可。

由于 kube_job_status_failed 和 kube_job_status_start_time 指標(biāo)中并不包含所屬 CronJob 的標(biāo)簽,所以第一步需要加入這個(gè)標(biāo)簽,而 kube_job_owner 指標(biāo)中的 owner_name 就是我們需要的,可以用下面的 promql 語(yǔ)句來(lái)進(jìn)行合并:

復(fù)制
max(  kube_job_status_start_time
  * ON(job_name, namespace) GROUP_RIGHT()  kube_job_owner{owner_name != ""}
  )BY (job_name, owner_name, namespace)1.2.3.4.5.6.

這里我們使用 max 函數(shù)是因?yàn)槲覀兛赡軙?huì)因?yàn)?HA 運(yùn)行多個(gè) kube-state-metrics,所以用 max 函數(shù)來(lái)返回每個(gè) Job 任務(wù)的一個(gè)結(jié)果即可。假設(shè)我們的 Job 歷史記錄包含 2 個(gè)任務(wù)(一個(gè)失敗,另一個(gè)成功),結(jié)果將如下所示:

復(fù)制
{job_name="hello-1623578940", namespace="myNamespace", owner_name="hello"} 1623578959{job_name="hello-1617667200", namespace="myNamespace", owner_name="hello"} 16176672041.2.

現(xiàn)在我們知道每個(gè) Job 的所有者了,接著我們需要找出最后執(zhí)行的任務(wù),我們可以通過(guò)按 owner_name 標(biāo)簽聚合結(jié)果來(lái)實(shí)現(xiàn)這一點(diǎn):

復(fù)制
max(  kube_job_status_start_time
  * ON(job_name,namespace) GROUP_RIGHT()  kube_job_owner{owner_name!=""}
) 
BY (owner_name)1.2.3.4.5.6.

上面這條語(yǔ)句會(huì)找到每個(gè) owner(也就是 CronJob)最新的任務(wù)開(kāi)始時(shí)間,然后再和上面的語(yǔ)句進(jìn)行合并,保留開(kāi)始時(shí)間相同的記錄即為最新執(zhí)行的 Job 任務(wù)了:

復(fù)制
max( kube_job_status_start_time
 * ON(job_name,namespace) GROUP_RIGHT() kube_job_owner{owner_name!=""}
)BY (job_name, owner_name, namespace)
== ON(owner_name) GROUP_LEFT()max( kube_job_status_start_time
 * ON(job_name,namespace) GROUP_RIGHT() kube_job_owner{owner_name!=""}
)BY (owner_name)1.2.3.4.5.6.7.8.9.10.11.12.13.

結(jié)果將顯示每個(gè) CronJob 最后執(zhí)行的作業(yè),并且僅顯示最后一個(gè):

復(fù)制
{job_name="hello-1623578940", namespace="myNamespace", owner_name="hello"} 16235789591.

為了增加可讀性我們還可以將 job_name、owner_name 標(biāo)簽替換為 job 和 cronjob,這樣更容易看明白:

復(fù)制
label_replace(  label_replace(    max(      kube_job_status_start_time
      * ON(job_name,namespace) GROUP_RIGHT()      kube_job_owner{owner_name!=""}
    )    BY (job_name, owner_name, namespace)
    == ON(owner_name) GROUP_LEFT()    max(      kube_job_status_start_time
      * ON(job_name,namespace) GROUP_RIGHT()      kube_job_owner{owner_name!=""}
    )    BY (owner_name),  "job", "$1", "job_name", "(.+)"),"cronjob", "$1", "owner_name", "(.+)")1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.

現(xiàn)在將會(huì)看到類似于下面的結(jié)果:

復(fù)制
{job="hello-1623578940", cronjob="hello", job_name="hello-1623578940", namespace="myNamespace", owner_name="hello"} 16235789591.

由于上面的查詢語(yǔ)句比較復(fù)雜,如果每次報(bào)警評(píng)估的時(shí)候都去進(jìn)行一次實(shí)時(shí)計(jì)算會(huì)對(duì) Prometheus 產(chǎn)生非常大的壓力,這里我們可以借助記錄規(guī)則來(lái)實(shí)現(xiàn)類離線計(jì)算的方式,大大提高效率,創(chuàng)建如下所示的記錄規(guī)則,用來(lái)表示獲取每個(gè) CronJob 最后執(zhí)行的作業(yè)記錄:

復(fù)制
- record: job:kube_job_status_start_time:max
  expr: |    label_replace(      label_replace(        max(          kube_job_status_start_time
          * ON(job_name,namespace) GROUP_RIGHT()          kube_job_owner{owner_name!=""}
        )        BY (job_name, owner_name, namespace)
        == ON(owner_name) GROUP_LEFT()        max(          kube_job_status_start_time
          * ON(job_name,namespace) GROUP_RIGHT()          kube_job_owner{owner_name!=""}
        )        BY (owner_name),      "job", "$1", "job_name", "(.+)"),    "cronjob", "$1", "owner_name", "(.+)")1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.

現(xiàn)在我們知道了 CronJob 最近開(kāi)始執(zhí)行的 Job 了,那么想要過(guò)濾出失敗的,則再使用 kube_job_status_failed 指標(biāo)就可以了:

復(fù)制
- record: job:kube_job_status_failed:sum
  expr: |    clamp_max(job:kube_job_status_start_time:max, 1)
      * ON(job) GROUP_LEFT()      label_replace(
        (kube_job_status_failed > 0),        "job", "$1", "job_name", "(.+)"
      )1.2.3.4.5.6.7.8.

這里使用 clamp_max 函數(shù)將 job:kube_job_status_start_time:max 的結(jié)果轉(zhuǎn)換為一組上限為 1 的時(shí)間序列,使用它來(lái)通過(guò)乘法過(guò)濾失敗的作業(yè),得到包含一組最近失敗的 Job 任務(wù),這里我們也添加到名為 kube_job_status_failed:sum 的記錄規(guī)則中。

最后一步就是直接為失敗的 Job 任務(wù)添加報(bào)警規(guī)則,如下所示:

復(fù)制
- alert: CronJobStatusFailed
  expr: |    job:kube_job_status_failed:sum
    * ON(cronjob, namespace) GROUP_LEFT()
    (kube_cronjob_spec_suspend == 0)1.2.3.4.5.

為避免誤報(bào),我們已將掛起的任務(wù)排除在外了。到這里我們就解決了 Prometheus 監(jiān)控 CronJob 的任務(wù)誤報(bào)的問(wèn)題,雖然 kube-prometheus 為我們內(nèi)置了大量的監(jiān)控報(bào)警規(guī)則,但是也不能完全迷信,有時(shí)候并不一定適合實(shí)際的需求。