Bones pràctiques per als contenidors Kubernetes: controls de salut

Bones pràctiques per als contenidors Kubernetes: controls de salut

TL; DR

  • Per aconseguir una alta observabilitat de contenidors i microserveis, els registres i les mètriques primàries no són suficients.
  • Per a una recuperació més ràpida i una major resiliència, les aplicacions haurien d'aplicar el principi d'alta observabilitat (HOP).
  • A nivell d'aplicació, NOP requereix: un registre adequat, un seguiment proper, comprovacions de seny i un seguiment del rendiment/transició.
  • Utilitzeu xecs com a element de NOR Sonda de preparació и Sonda de vivacitat Kubernetes.

Què és una plantilla de control de salut?

Quan es dissenya una aplicació crítica de missió i altament disponible, és molt important pensar en un aspecte com la tolerància a fallades. Una aplicació es considera tolerant a errors si es recupera ràpidament d'una fallada. Una aplicació típica al núvol utilitza una arquitectura de microserveis, on cada component es col·loca en un contenidor independent. I per assegurar-vos que l'aplicació a k8s estigui altament disponible quan dissenyeu un clúster, heu de seguir certs patrons. Entre ells hi ha la Plantilla de comprovació de salut. Defineix com l'aplicació comunica a k8s que és saludable. Aquesta no només és informació sobre si el pod s'està executant, sinó també sobre com rep i respon a les sol·licituds. Com més sap Kubernetes sobre la salut del pod, més intel·ligents prendrà les decisions sobre l'encaminament del trànsit i l'equilibri de càrrega. Així, el Principi d'Alta Observabilitat permet a l'aplicació respondre a les sol·licituds de manera oportuna.

Principi d'alta observabilitat (HOP)

El principi d'alta observabilitat n'és un principis per dissenyar aplicacions en contenidors. En una arquitectura de microserveis, als serveis no els importa com es processa la seva sol·licitud (i amb raó), però el que importa és com reben les respostes dels serveis receptors. Per exemple, per autenticar un usuari, un contenidor envia una sol·licitud HTTP a un altre, esperant una resposta en un format determinat, això és tot. PythonJS també pot processar la sol·licitud i Python Flask pot respondre. Els contenidors són com caixes negres amb contingut ocult entre si. No obstant això, el principi NOP requereix que cada servei exposi diversos punts finals de l'API que indiquin com de saludable és, així com el seu estat de preparació i tolerància a errors. Kubernetes demana aquests indicadors per pensar en els propers passos per a l'encaminament i l'equilibri de càrrega.

Una aplicació al núvol ben dissenyada registra els seus esdeveniments principals mitjançant els fluxos d'E/S estàndard STDERR i STDOUT. A continuació ve un servei auxiliar, per exemple, filebeat, logstash o fluentd, que lliura registres a un sistema de control centralitzat (per exemple, Prometheus) i un sistema de recollida de registres (el conjunt de programari ELK). El diagrama següent mostra com funciona una aplicació al núvol segons el patró de prova de salut i el principi d'alta observabilitat.

Bones pràctiques per als contenidors Kubernetes: controls de salut

Com aplicar el patró de comprovació de salut a Kubernetes?

Fora de la caixa, k8s supervisa l'estat dels pods mitjançant un dels controladors (Desplegaments, Conjunts de rèpliques, DaemonSets, StatefulSets etc., etc.). Després d'haver descobert que el pod ha caigut per algun motiu, el controlador intenta reiniciar-lo o moure'l a un altre node. Tanmateix, un pod pot informar que està en funcionament, però no funciona. Posem un exemple: la vostra aplicació utilitza Apache com a servidor web, heu instal·lat el component en diversos pods del clúster. Com que la biblioteca es va configurar incorrectament, totes les sol·licituds a l'aplicació responen amb el codi 500 (error intern del servidor). Quan comproveu el lliurament, comprovar l'estat de les beines dóna un resultat satisfactori, però els clients pensen de manera diferent. Descriurem aquesta situació indesitjable de la següent manera:

Bones pràctiques per als contenidors Kubernetes: controls de salut

En el nostre exemple, k8s ho fa comprovació de la funcionalitat. En aquest tipus de verificació, el kubelet comprova contínuament l'estat del procés al contenidor. Un cop entengui que el procés s'ha aturat, el reiniciarà. Si l'error es pot resoldre simplement reiniciant l'aplicació i el programa està dissenyat per tancar-se en qualsevol error, tot el que necessiteu és una comprovació de l'estat del procés per seguir el NOP i el patró de prova de salut. L'única llàstima és que no tots els errors s'eliminen reiniciant. En aquest cas, k8s ofereix dues maneres més profundes d'identificar problemes amb el pod: Sonda de vivacitat и Sonda de preparació.

LivenessProbe

Durant la Sonda de vivacitat kubelet realitza 3 tipus de comprovacions: no només determina si el pod s'està executant, sinó també si està preparat per rebre i respondre adequadament a les sol·licituds:

  • Configureu una sol·licitud HTTP al pod. La resposta ha de contenir un codi de resposta HTTP entre 200 i 399. Per tant, els codis 5xx i 4xx indiquen que el pod té problemes, tot i que el procés s'està executant.
  • Per provar pods amb serveis que no són HTTP (per exemple, el servidor de correu Postfix), heu d'establir una connexió TCP.
  • Executeu una ordre arbitrària per a un pod (internament). La comprovació es considera correcta si el codi de finalització de l'ordre és 0.

Un exemple de com funciona això. La següent definició de pod conté una aplicació NodeJS que genera un error 500 a les sol·licituds HTTP. Per assegurar-nos que el contenidor es reinicia quan rebem aquest error, utilitzem el paràmetre livenessProbe:

apiVersion: v1
kind: Pod
metadata:
 name: node500
spec:
 containers:
   - image: magalix/node500
     name: node500
     ports:
       - containerPort: 3000
         protocol: TCP
     livenessProbe:
       httpGet:
         path: /
         port: 3000
       initialDelaySeconds: 5

Això no és diferent de qualsevol altra definició de pod, però estem afegint un objecte .spec.containers.livenessProbe... Paràmetre httpGet accepta la ruta a la qual s'envia la sol·licitud HTTP GET (al nostre exemple això és /, però en escenaris de combat hi pot haver alguna cosa així /api/v1/status). Un altre livenessProbe accepta un paràmetre initialDelaySeconds, que indica a l'operació de verificació que esperi un nombre especificat de segons. El retard és necessari perquè el contenidor necessita temps per començar i, quan es reinicia, no estarà disponible durant un temps.

Per aplicar aquesta configuració a un clúster, utilitzeu:

kubectl apply -f pod.yaml

Després d'uns segons, podeu comprovar el contingut del pod mitjançant l'ordre següent:

kubectl describe pods node500

Al final de la sortida, trobeu això és.

Com podeu veure, livenessProbe va iniciar una sol·licitud HTTP GET, el contenidor va generar un error 500 (que és el que estava programat per fer) i el kubelet el va reiniciar.

Si us pregunteu com es va programar l'aplicació NideJS, aquí teniu l'app.js i el Dockerfile que es van utilitzar:

app.js

var http = require('http');

var server = http.createServer(function(req, res) {
    res.writeHead(500, { "Content-type": "text/plain" });
    res.end("We have run into an errorn");
});

server.listen(3000, function() {
    console.log('Server is running at 3000')
})

Dockerfile

FROM node
COPY app.js /
EXPOSE 3000
ENTRYPOINT [ "node","/app.js" ]

És important tenir en compte això: livenessProbe només reiniciarà el contenidor si falla. Si un reinici no corregeix l'error que impedeix que el contenidor s'executi, el kubelet no podrà prendre mesures per corregir el problema.

Sonda de preparació

readinessProbe funciona de manera similar a livenessProbes (sol·licituds GET, comunicacions TCP i execució d'ordres), excepte per a les accions de resolució de problemes. El contenidor en què es detecta l'error no es reinicia, sinó que està aïllat del trànsit entrant. Imagineu que un dels contenidors està realitzant molts càlculs o està sota una gran càrrega, fent que els temps de resposta augmenten. En el cas de livenessProbe, s'activa la comprovació de disponibilitat de la resposta (mitjançant el paràmetre de comprovació timeoutSeconds), després del qual el kubelet reinicia el contenidor. Quan s'inicia, el contenidor comença a realitzar tasques intensives en recursos i es reinicia de nou. Això pot ser fonamental per a aplicacions que necessiten velocitat de resposta. Per exemple, un cotxe mentre està a la carretera espera una resposta del servidor, la resposta es retarda i el cotxe té un accident.

Escrivim una definició de redinessProbe que establirà el temps de resposta de la sol·licitud GET en no més de dos segons i l'aplicació respondrà a la sol·licitud GET al cap de 5 segons. El fitxer pod.yaml hauria de tenir aquest aspecte:

apiVersion: v1
kind: Pod
metadata:
 name: nodedelayed
spec:
 containers:
   - image: afakharany/node_delayed
     name: nodedelayed
     ports:
       - containerPort: 3000
         protocol: TCP
     readinessProbe:
       httpGet:
         path: /
         port: 3000
       timeoutSeconds: 2

Despleguem un pod amb kubectl:

kubectl apply -f pod.yaml

Esperem un parell de segons i veurem com funcionava ReadinessProbe:

kubectl describe pods nodedelayed

Al final de la sortida podeu veure que alguns dels esdeveniments són similars aquest.

Com podeu veure, kubectl no va reiniciar el pod quan el temps de comprovació va superar els 2 segons. En canvi, va cancel·lar la sol·licitud. Les comunicacions entrants es redirigien a altres pods que funcionen.

Tingueu en compte que ara que el pod s'ha descarregat, kubectl torna a dirigir-hi les sol·licituds: les respostes a les sol·licituds GET ja no es retarden.

Com a comparació, a continuació es mostra el fitxer app.js modificat:

var http = require('http');

var server = http.createServer(function(req, res) {
   const sleep = (milliseconds) => {
       return new Promise(resolve => setTimeout(resolve, milliseconds))
   }
   sleep(5000).then(() => {
       res.writeHead(200, { "Content-type": "text/plain" });
       res.end("Hellon");
   })
});

server.listen(3000, function() {
   console.log('Server is running at 3000')
})

TL; DR
Abans de l'arribada de les aplicacions al núvol, els registres eren el mitjà principal per supervisar i comprovar l'estat de l'aplicació. Tanmateix, no hi havia cap mitjà per prendre cap acció correctiva. Els registres encara són útils avui dia; s'han de recollir i enviar a un sistema de recollida de registres per analitzar situacions d'emergència i prendre decisions. [Tot això es podria fer sense aplicacions al núvol que fessin servir monit, per exemple, però amb k8s es va fer molt més fàcil :) - nota de l'editor. ]

Avui dia, les correccions s'han de fer gairebé en temps real, de manera que les aplicacions ja no han de ser caixes negres. No, haurien de mostrar punts finals que permetin als sistemes de monitorització consultar i recopilar dades valuoses sobre l'estat dels processos perquè puguin respondre a l'instant si cal. Això s'anomena Patró de disseny de la prova de rendiment, que segueix el principi d'alta observabilitat (HOP).

Kubernetes ofereix de manera predeterminada dos tipus de comprovacions de salut: ReadinessProbe i LivenessProbe. Tots dos utilitzen els mateixos tipus de comprovacions (sol·licituds HTTP GET, comunicacions TCP i execució d'ordres). Es diferencien en quines decisions prenen en resposta als problemes a les beines. livenessProbe reinicia el contenidor amb l'esperança que l'error no es torni a produir i ReadinessProbe aïlla el pod del trànsit entrant fins que es resolgui la causa del problema.

El disseny adequat de l'aplicació hauria d'incloure els dos tipus de comprovació i assegurar-se que recopilen dades suficients, especialment quan es produeix una excepció. També hauria de mostrar els punts finals de l'API necessaris que proporcionen al sistema de monitorització (Prometheus) mètriques de salut importants.

Font: www.habr.com

Afegeix comentari