Kubernetes Jobs

Un Job è un oggetto che crea uno o più pod, i quali eseguono una sola volta poi terminano.

Semplice Job

Esempio: un job che calcola il valore di Pi Greco a 2000 cifre decimali.

Scriviamo il Manifest:

vim ~/scripts/jobpi.yml
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

Li parametro backoffLimit è il numero massimo di riprove prima di dichiarare fallimento definitivo, con valore di default 6.

Sottoponiamo il manifest a Kubernetes:

kubectl apply -f ~/scripts/jobpi.yml

Controlliamo l'esistenza:

kubectl get job

e del pod sottostante:

kubectl get pod

I Job si possono descrivere:

kubectl describe job pi

Quando un Job termina lo si vede dalla colonna COMPLETIONS. Quando il suo pod termina va nello stato Completed.

Per listare tutti i pod non Completed (ancora attivi) che appartengono ad un Job si può usare l'espressione:

pods=$(kubectl get pods --selector=batch.kubernetes.io/job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods

Per vedere l'output dei pod di un Job si può usare:

kubectl logs jobs/pi
3.141592653589793238462643383279502884197169.....

Rimuoviamo il Job tramite Manifest:

kubectl delete -f ~/scripts/jobpi.yml

La rimozione di un job rimuove i suoi pod.

CronJob

Un CronJob compie attività a intervalli regolari schedulati nel futuro.

E' l'equivalente dell'ambiente cron nel mondo Unix/Linux.

Esempio. Un cronJob che scrive l'ora corrente e un messaggio ogni minuto.

vim ~/scripts/cronjob.yml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox:1.28
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

A intervalli di un minuto viene creato un nuovo pod che esegue il comando specificato.

La schedulazione è data dal campo .spec.schedule, che ha lo stesso formato del cron di Unix.

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
# │ │ │ │ │                                   OR sun, mon, tue, wed, thu, fri, sat
# │ │ │ │ │ 
# │ │ │ │ │
# * * * * *

Sono disponibili delle macro:

MacroEquivalente a
@yearly0 0 1 1 *
@monthly0 0 1 * *
@weekly0 0 * * 0
@daily0 0 * * *
@hourly0 * * * *

Il campo .spec.jobTemplate ha lo stesso schema di un Job. Si possono anche usare in esso metadati come labels e annotations.

Sottomettiamo il Manifest:

kubectl apply -f ~/scripts/cronjob.yml

Controlliamo l'esistenza del CronJob:

kubectl get cronjob
NAME    SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   * * * * *   False     0        14s             30s

Dopo qualche minuto controlliamo i Job e i Pod:

kubectl get cronjobs
kubectl get jobs
kubectl get pods

Notare che il nome è costruito a partire dal nome del CronJob.

I nostri pod del Cronjob scrivono ciascuno al suo standard output, quindi nei logs. L'output di un pod è visibile con, p.es.:

kubectl logs hello-28474168-pdh77
Tue Feb 20 17:38:04 UTC 2024
Hello from the Kubernetes cluster

Calibrazione dei Job

Storia dei Job

Anche dopo molti minuti il rapporto mantiene una storia di poche entries. La storia mantenuta è controllata dai parametri:

  • .spec.successfulJobsHistoryLimit - lunghezza della storia dei jobs/pods che hanno avuto successo (default 3)
  • .spec.failedJobsHistoryLimit - lunghezza della storia dei jobs/pods che sono falliti (default 1)

Partenza Ritardata dei Job

Il campo opzionale .spec.startingDeadlineSeconds definisce una tolleranza in secondi per la partenza di un job (default: infinito), se per qualsiasi ragione il job non riesce a partire al momento schedulato.

Non settare mai il parametro inferiore a 10 secondi, o il job può non venire mai eseguito.

Se passa il tempo di tolleranza il job è considerato fallito.

Concorrenza

E' quando il job precedente è ancora in esecuzione e viene schedulato un nuovo job uguale.

Questo è controllato dal parametro .spec.concurrencyPolicy che può avere i seguenti valori:

  • Allow - (default) concesso
  • Forbid - proibito. Il nuovo job schedulato fallisce.
  • Replace - il nuovo job schedulato parte. Il vecchio job non ancora completato, fallisce.

Sospensione

Si può sospendere l'esecuzione di un Job o CronJob settando il parametro .spec.suspend al valore true (default: false).

I job già partiti non sono toccati.

Si possono cambiare i cronjob già attivi, oltre che modificare e sottomettere il Manifest. Per esempio:

kubectl patch cronjob hello -p '{"spec":{"suspend":true}}'

La stringa di patch può essere in Json o Yaml.

ATTENZIONE: Quando un CronJob è sospeso e passano i momenti di schedulazione dei suoi Job, questi vengono accodati. Quando si toglie la sospensione i Job accodati vengono eseguiti simultaneamente. Il comportamento dipende dai settaggi .spec.startingDeadlineSeconds e .spec.concurrencyPolicy.

Terminare l'Esercizio

kubectl delete -f ~/scripts/cronjob.yml