EN EnglishDE Deutsch

Kubernetes: CronJobs überwachen

Kubernetes: CronJobs überwachen
Foto von Ahmed Rajgoli Shoaib Shakeel / Unsplash

Wie lange ist es her, seit ein Kubernetes CronJob zuletzt erfolgreich gelaufen ist?
Heute ein kurzer Blogbeitrag zum Monitoring von Kubernetes CronJobs.

Der heutige Blog ist für Sie interessant, wenn Sie Ihre Kubernetes CronJobs mit dem verbreiteten Monitoring-Stack des Prometheus Operators (Prometheus Agent, Service Discovery, Grafana) überwachen möchten.
opensight.ch – roman hüsler

Grafana-Dashboard mit drei Panels, die für drei CronJobs die Minuten seit der letzten erfolgreichen Ausführung als Sägezahnkurve zeigen
Kubernetes CronJobs - Zeit seit der letzten erfolgreichen Ausführung

Kubernetes CronJobs

Diagramm: ein CronJob erzeugt mehrere Jobs, und jeder Job erzeugt mehrere Pods
Kubernetes CronJobs

Ein CronJob legt in Kubernetes einen Zeitplan fest (ganz ähnlich wie Cron Jobs unter Linux), nach dem ein Job periodisch ausgeführt werden soll. Ist der Ausführungszeitpunkt erreicht, erstellt Kubernetes automatisch ein Job-Objekt, das wiederum einen oder mehrere Pods für die Ausführung erzeugt. Uns interessiert also, wann der Job zuletzt gestartet wurde und ob der Lauf (Pod) erfolgreich abgeschlossen wurde. Auf Kubernetes-Seite haben wir es mit Objekten vom Typ «CronJob», «Job» und «Pod» zu tun.

Die Herausforderung: Die gewünschte Information lässt sich nicht einfach aus einer einzigen Metrik abfragen, sondern mehrere Metriken müssen kombiniert werden. Wir verwenden die folgenden 4 Metriken, um ans Ziel zu kommen:

  • kube_job_status_start_time
  • kube_job_labels
  • kube_pod_labels
  • kube_pod_status_phase

Voraussetzungen für das CronJob-Monitoring

Zuerst sollten wir das Kubernetes-Manifest unseres CronJobs mit einigen Labels versehen, damit wir genau diesen Job später in den Metriken wiederfinden:

cronjob.yaml in GitLab: das Label cronjob: stockscores-updater ist sowohl in den Metadaten des jobTemplate als auch des Pod-Templates gesetzt
Bild - YAML-Manifest des CronJobs - Job-Labels

Metriken kombinieren

Grafana Explore mit der Query kube_job_status_start_time für die stockscores-updater-Jobs und ihren Unix-Timestamps
Bild - Metrik kube_job_status_start_time
kube_job_status_start_time{job_name=~"stockscores-updater.*"}

Die Metrik «kube_job_status_start_time» liefert den Unix-Timestamp der letzten Job-Ausführungen, die der CronJob erzeugt hat. Aber welche davon wurden mit dem Status «Succeeded» abgeschlossen? Um das herauszufinden, muss man die Jobs den erzeugten Pods zuordnen und deren Status abfragen.

Zuerst suchen wir in der Metrik «kube_job_labels» alle vom CronJob erzeugten Jobs mit dem Label «cronjob=stockscores-updater» (siehe Voraussetzungen) und kombinieren sie mit der Metrik von oben (kube_job_status_start_time). Wegen des GROUP_RIGHT-Statements hat die Metrik «kube_job_labels» die höhere Kardinalität: Wir arbeiten mit ihren Labels weiter, aber mit dem Metrikwert (Unix-Timestamp) von kube_job_status_start_time.

kube_job_status_start_time
  * ON(job_name) GROUP_RIGHT()
    kube_job_labels{label_cronjob="stockscores-updater"}

Jetzt suchen wir in der Metrik der Pod-Labels alle Pods mit dem Label «cronjob=stockscores-updater» (siehe Voraussetzungen):

kube_pod_labels{label_cronjob=~"stockscores-updater"}
Grafana-Tabelle der Metrik kube_pod_labels, hervorgehoben sind die Spalten label_job_name und pod
Bild - Metrik kube_pod_labels

Hier sehen wir, dass das Label leider «label_job_name» heisst. Eigentlich müsste es «job_name» heissen, damit wir es zuordnen und unsere Query von oben weiterführen können. Wir brauchen also «label_replace»…

kube_job_status_start_time
  * ON(job_name) GROUP_RIGHT()
    kube_job_labels{label_cronjob="stockscores-updater"}
    * ON(job_name) GROUP_RIGHT()
      label_replace(kube_pod_labels, "job_name", "$1", "label_job_name", "(.*)")

Nun ist die Query so weit, dass wir den Pod-Namen der letzten Startzeit des Jobs zuordnen können. Jetzt filtern wir nur noch die Einträge heraus, bei denen auch die Ausführung des Pods erfolgreich abgeschlossen wurde:

kube_job_status_start_time
  * ON(job_name) GROUP_RIGHT()
    kube_job_labels{label_cronjob="stockscores-updater"}
    * ON(job_name) GROUP_RIGHT()
      label_replace(kube_pod_labels, "job_name", "$1", "label_job_name", "(.*)")
      * ON(pod) GROUP_RIGHT()
        kube_pod_status_phase{job="kube-state-metrics",phase=~"Succeeded"}

Kubernetes CronJob Monitoring - Fazit

An diesem Punkt haben wir eine Metrik mit dem Unix-Timestamp (Startzeit) aller erfolgreich ausgeführten Pods des CronJobs. Daraus können wir nun die Zeit seit der letzten erfolgreichen Ausführung berechnen, und unser Kubernetes CronJob Monitoring ist fertig.

# k8s cronjob - time since last successful execution
time() - max(
  kube_job_status_start_time
  * ON(job_name) GROUP_RIGHT()
    kube_job_labels{label_cronjob="stockscores-updater"}
    * ON(job_name) GROUP_RIGHT()
      label_replace(kube_pod_labels, "job_name", "$1", "label_job_name", "(.*)")
      * ON(pod) GROUP_RIGHT()
        kube_pod_status_phase{job="kube-state-metrics",phase=~"Succeeded"}
  )
  BY (job_name, label_cronjob)

Das ergibt in der Regel das klassische Sägezahnmuster, das die Zeit seit der letzten erfolgreichen Ausführung zeigt.

Grafana-Dashboard: Sägezahnkurven der Minuten seit der letzten erfolgreichen Ausführung für drei CronJobs, mit grünen und roten Schwellwertbereichen
Bild - Grafana-Dashboard, verstrichene Zeit seit der letzten erfolgreichen CronJob-Ausführung

Wir hoffen, Sie haben einige Einblicke ins Monitoring von Kubernetes CronJobs gewonnen. Für das grosse Ganze, von der Hardware bis zu den Workloads, lesen Sie unseren Kubernetes-Monitoring-Leitfaden. Weitere DevOps-Blogs finden Sie unter opensight.ch/blog/category/devops