Controllo di Sanità e Probes
Kubernetes fornisce due tipi di sonde (probes) per testare l'usabilità di un applicativo: Liveness Probes e Readiness Probes.
Un Liveness Probe testa se l'applicativo è vivo e raggiungibile. Se non lo è, il pod che lo implementa viene terminato e ristartato.
Un Readiness Probe testa se l'applicativo può ricevere traffico del tipo programmato, Se non può, non viene inviato traffico al pod che lo implementa.
Vi sono tre tipi di probe; HTTP, Comando e TCP.
- HTTP - Kubernetes accede ad un path HTTP del pod, e se il responso ha i codici tra il 200 e il 300 lo considera attivo. Un pod può implementare un miniserver HTTP a questo solo scopo.
- Command - viene eseguito un comando nel pod, e se ritorna un codice di ritorno 0 viene considerato attivo.
- TCP - viene aperta una connessione al pod, e se ha successo il pod è considerato attivo.
Command Liveness
Esempio di Liveness Probe:
vim ~/scripts/liveness.yml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: registry.k8s.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 40; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
I parametri sono:
initialDelaySeconds
- quanto tempo attendere prima di inviare il primo probeperiodSeconds
- ogni quanto tempo inviare i probe
Sottomettere il manifest:
kubectl apply -f ~/scripts/liveness.yml
Ispezionare gli eventi del pod:
kubectl describe pod liveness-exec
Kubernetes inizia subito ad inviare liveness probes, anche quando il pod non è in stato di Running
. Quindi possono esservi degli eventi di fallimento iniziali. Possono essere gestiti aumentando il parametro initialDelaySeconds
.
Dopo un certo periodo di tempo il pod è stabile e il rapporto da:
kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 7 (78s ago) 20m
In caso di fallimento si vede un esempio di questo tipo:
Warning Unhealthy 7m17s (x19 over 16m) kubelet Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Warning BackOff 2m27s (x22 over 9m17s) kubelet Back-off restarting failed container liveness in pod liveness-exec_default(0726f57d-8dd9-489d-b0c5-ff352bfdc084)
E il pod è:
kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness-exec 0/1 CrashLoopBackOff 7 (5m11s ago) 17m
Terminare il pod:
kubectl delete -f ~/scripts/liveness.yml
HTTP Liveness
Esempio:
vim ~/scripts/http-liveness.yml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: registry.k8s.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
L'immagine registry.k8s.io/liveness
è appositamente didattica.
E' stata scritta in linguaggio Go e contiene il route handler:
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
Il responso è appositamente accurato per i primi 10 secondi, ma poi fallisce. Con un Liveness Probe il pod viene ristartato.
Sottomettiamo il manifest:
kubectl apply -f ~/scripts/http-liveness.yml
E ben presto abbiamo una situazione di questo tipo:
kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness-http 1/1 Running 2 (13s ago) 75s
Con l'evento dedotto da:
kubectl describe pod liveness-http
.....
Warning Unhealthy 1s (x4 over 28s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 500
Terminiamo l'esercizio:
kubectl delete -f ~/scripts/http-liveness.yml
HTTP Readiness
Una leggera modifica alle specifiche di liveness:
vim ~/scripts/http-readiness.yml
apiVersion: v1
kind: Pod
metadata:
labels:
test: readiness
name: readiness-http
spec:
containers:
- name: readiness
image: registry.k8s.io/liveness
args:
- /server
readinessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
Sottomettere il manifest:
kubectl apply -f ~/scripts/http-readiness.yml
Inizialmente il pod si comporta come prima, e dopo 10 secondi fallisce. Kubernetes lo dichiara fallito e non lo ristarta.
Il rapporto di eventi è:
kubectl describe pod readiness-http
.....
Warning Unhealthy 18s (x21 over 75s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 500
E il pod:
kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-http 0/1 Running 0 2m5s
Pulire l'esercizio:
kubectl delete -f ~/scripts/http-readiness.yml
TCP Liveness e Readiness
Prepariamo un manifest:
vim ~/scripts/tcp-liveness-readiness.yml
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: registry.k8s.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
Ha entrambi i tipi di probe, a scopo didattico per notare che non vi è differenza sintattica ma solo di comportamento. Basta uno o l'altro probe.
Kubernetes prova un'apertura di connessione alla porta 8080. Se ha successo il pod è alive/ready.
Sottomettiamo il manifest:
kubectl apply -f ~/scripts/tcp-liveness-readiness.yml
Non vi sono eventi di errore dopo tempo ragguardevole. Il pod sta bene.
Terminiamo l'esercizio:
kubectl delete -f ~/scripts/tcp-liveness-readiness.yml