Abbiamo imparato sinora (e componenti come il ReplicaSet ce l'hanno dimostrato in pratica) che una delle peculiarità di Kubernetes consiste nel saper tenere in vita le applicazioni. Se con la configurazione dichiarativa richiediamo che una certa componente debba rimanere in vita in uno specifico numero di istanze, nel caso in cui alcune di queste fallissero, Kubernetes provvederebbe al loro riavvio.
Questo potrebbe darci l'impressione - ed in buona parte le cose stanno così - che Kubernetes sia perfettamente in grado di mantenere in vita l'applicazione. Vero: il problema però è che tale tipo di attività di controllo agisce a livello di processo pertanto si limita a verificare che la componente sia running, non che stia funzionando adeguatamente.
Se ad esempio attiviamo un server Web, l'applicativo in se può essere in esecuzione ma per qualche motivo potrebbe non contenere nella document root
le pagine Web necessarie al buon funzionamento del progetto o potrebbero esserci errori negli script PHP inseriti. Quindi un conto è avere disponibile il processo a livello di sistema, un conto è che tutte le risorse a sua disposizione siano adeguatamente funzionanti per soddisfare correttamente le richieste dei client e completare le elaborazioni.
Quando vogliamo andare oltre i normali controlli e verificare l'effettivo stato di "salute" dell'applicazione ricorriamo ad un meccanismo noto come health check che può essere dettagliato nella configurazione YAML delle componenti, anche a livello Pod.
Esempio di health check
Non esiste una sola tipologia di health check ma una delle prime che si impara, anche per la sua utilità in generale, è il liveness probe. In questo caso, definiamo un'azione da svolgere, ad esempio una funzionalità da invocare sul processo in esecuzione, affinché venga stabilito che il processo non solo sia vivo ma stia lavorando correttamente.
Nel seguente esempio prepariamo un'applicazione server (il nostro container è basato su Node.js ma si potrebbe replicare l'esempio su qualsiasi altra tecnologia) che per dimostrare di essere funzionante deve rispondere al path /controllo
.
Prepariamo il file YAML di configurazione che chiameremo pod-hc.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: node-app
spec:
containers:
- name: node-app
image: docker.io/library/node-app:latest
imagePullPolicy: Never
livenessProbe:
httpGet:
path: /controllo
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
Inseriamo il tutto in un normale Pod e vediamo che nella sezione livenessProbe
troviamo le specifiche della richiesta HTTP GET(httpGet
) che dovranno essere seguite per effettuare un controllo dello stato di salute dell'applicazione. Nel nostro caso l'endpoint incaricato è /controllo
, immaginando di non coinvolgerne altri deputati alla vera logica dell'applicazione. Abbiamo scelto la porta 8080/TCP ma questo dipende dal nostro container.
Specifichiamo che come risposta positiva all'health check, l'endpoint deve restituire un codice HTTP di successo quindi maggiore o uguale a 200 e inferiore a 400: tale risultato può essere impostato all'interno del nostro applicativo.
Da notare le due impostazioni initialDelaySeconds
e periodSeconds
che servono a configurare la temporizzazione dei controlli: il primo indica dopo quanto tempo può iniziare l'attività di health check (per permettere ad esempio le opportune inizializzazioni), la seconda scandisce la periodicità della verifica.
Lanciare il Pod
Una volta fatto questo, possiamo lanciare il Pod con la consueta istruzione kubectl apply -f pod-hc.yaml
e, dopo pochi istanti, si potrà controllare l'effettiva attivazione dei controlli con describe
:
$ kubectl describe pods/node-app
Name: node-app
Namespace: default
...
...
Status: Running
IP: 10.244.0.3
IPs:
IP: 10.244.0.3
Containers:
node-app:
Image: docker.io/library/node-app:latest
...
...
Liveness: http-get http://:8080/controllo delay=3s timeout=1s period=3s
Rispetto al normale output di un Pod troviamo la voce Liveness
che sintetizza la configurazione che abbiamo assegnato. Per avere una rapida controprova del funzionamento sarà sufficiente modificare la configurazione del Pod inserendo nella riga path: /controllo
un endpoint non esistente, ad esempio path: /percorsosbagliato
e ciò comporterà il fallimento dell'health check. Sarà infatti sufficiente distruggere e riavviare il Pod per avere prova che esso viene riavviato di continuo ritenendolo non correttamente funzionante (notare la colonna RESTARTS
):
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
node-app 1/1 Running 3 (4s ago) 2m1s
mentre nell'output del describe
troveremo nella sezione Events
(in fondo) una voce del genere
Warning Unhealthy ... Liveness probe failed: HTTP probe failed with statuscode: 404
dove il codice HTTP 404 indica proprio una risorsa non trovata.