Quando si iniziano a studiare i container Docker, ed in particolare il loro impiego in applicazioni Kubernetes, ci si concentra su servizi long running.
Pensiamo, ad esempio, ai tipici casi di studio presi in considerazione sinora: abbiamo attinto ampiamente al settore dei server Web. Esistono casi però in cui vogliamo che il container esegua operazioni batch in grado di attivarsi, compiere un lavoro, terminare il proprio operato e chiudersi. Tipicamente, tutto questo avviene su chiamata manuale o su schedulazione in base ad eventi o temporizzata.
Attività di questo genere possono rivelarsi fondamentali in ambiti in cui, ad esempio, vogliamo lanciare un processo per l'analisi di dati: svolgerà il suo lavoro, salverà risultati e si chiuderà al termine. Lo stesso potremmo pensare per attività spot o periodiche o anche per reazione ad eventi specifici.
In un contesto rivolto all'impiego di container ciò consiste nell'inserimento dell'applicazione in un uno di questi nodi operativi, ciò non solo per coerenza con l'architettura in vigore ma anche perché, come abbiamo imparato ad apprezzare sinora, i container rappresentano un modo estremamente pratico per impacchettare un'applicazione con tutte le dipendenze e le risorse di cui ha bisogno e, soprattutto in casi di lavorazioni isolate, ciò permette di allestire al volo un ambiente operativo completo e dismetterlo al termine della necessità.
Lavori non long-running di questo genere prendono tipicamente il nome di Job ed in Kubernetes rappresentano una vera e propria componente di sistema.
Tipologie di Job
In Kubernetes, i Job sono classificabili in diverse tipologie e ciò che li distingue l'uno dall'altro sono essenzialmente due fattori: il numero di Pod in parallelo
che possono avere ed il numero di esecuzioni che devono completare.
In base a tali fattori, si distinguono tre diverse tipologie di Job:
- One shot: un singolo Pod da eseguire una volta fino a completamento. Pensiamo ad operazioni "one shot" nel vero senso dell'espressione come una migrazione di un database o il trasferimento di dati;
- Parallel fixed completions: esecuzione di uno o più Pod, una o più volte, fino al completamento di un numero fissato di esecuzioni. Pensiamo a lavori batch di processamento da eseguire in parallelo, ad esempio perché si ha a che fare con sorgenti multiple;
- Work queue: uno o più Pod in esecuzione parallela che eseguono task provenienti dalla stessa coda di lavoro. Come esempio, si può pensare a qualsiasi elaborazione di dati inseriti in un'unica coda (contesto molto comune in IoT), esecuzione distribuita, processamento di comunicazioni.
Struttura di un Job
Anche i Job possono essere lanciati con la configurazione dichiarativa e a questo punto non dovrebbe stupirci che in essa dobbiamo inserire:
apiVersion
che sarà pari abatch/v1
;- come
kind
,job
trattandosi di una componente a sé stante; - alcuni metadata per la specifica di etichette ed informazioni di contorno;
- un template dei Pod - uno o più a seconda del tipo di Job - che dovranno essere attivati per l'esecuzione. Il blocco
template
è incluso in un elementospec
all'interno del quale due attributi specificheranno i parametri di esecuzione del Job come prima dettagliato. Potremo infatti, a seconda dei casi, definireparallelism
(numero di Pod da attivare) ecompletions
(numero di completamenti da portare a termine).
Come esempio vediamo un Job di tipo Parallel fixed completions che li contempla entrambi (il file si chiamerà myjob.yaml
):
apiVersion: batch/v1
kind: Job
metadata:
name: job-example
spec:
parallelism: 2
completions: 3
template:
spec:
containers:
- name: mytask
image: docker.io/library/mytask:latest
imagePullPolicy: Never
restartPolicy: OnFailure
In questo caso, abbiamo stabilito un parallelismo di due Pod che richiedono tre completamenti delle operazioni. L'immagine è un semplice script di prova di nome mytask
che abbiamo importato in minikube dopo la compilazione in Docker ma può essere liberamente sostituito con uno script personalizzato che svolge semplici operazioni.
Con kubectl get jobs
possiamo verificare che il Job sia partito. Nel suo output vediamo che vengono contati anche i completamenti conseguiti:
NAME COMPLETIONS DURATION AGE
job-example 3/3 30s 2m15s
Nel nostro caso ne erano richiesti tre come si vede nel file YAML. Con kubectl get pods
possiamo via via verificare i Pod attivati in base al parallelismo che abbiamo richiesto.