Mellores prácticas para contedores Kubernetes: comprobacións de saúde

Mellores prácticas para contedores Kubernetes: comprobacións de saúde

TL, RD

  • Para lograr unha alta observabilidade dos contedores e microservizos, os rexistros e as métricas primarias non son suficientes.
  • Para unha recuperación máis rápida e unha maior resistencia, as aplicacións deben aplicar o Principio de Alta Observabilidade (HOP).
  • A nivel de aplicación, NOP require: rexistro adecuado, seguimento próximo, comprobacións de cordura e seguimento de rendemento/transición.
  • Use cheques como elemento de NOR ReadinessProbe и LivenessProbe Kubernetes.

Que é un modelo de comprobación de saúde?

Ao deseñar unha aplicación de misión crítica e altamente dispoñible, é moi importante pensar nun aspecto como a tolerancia a fallos. Unha aplicación considérase tolerante a fallos se se recupera rapidamente dunha falla. Unha aplicación típica na nube usa unha arquitectura de microservizos, onde cada compoñente se coloca nun contedor separado. E para asegurarse de que a aplicación en k8s estea moi dispoñible cando deseña un clúster, cómpre seguir certos patróns. Entre eles está o Modelo de comprobación de saúde. Define como a aplicación comunica a k8s que é saudable. Non se trata só de información sobre se o pod está funcionando, senón tamén sobre como recibe e responde ás solicitudes. Canto máis sabe Kubernetes sobre a saúde do pod, máis intelixentes tomará as decisións sobre o enrutamento do tráfico e o equilibrio de carga. Así, o Principio de Alta Observabilidade permite que a aplicación responda ás solicitudes de forma oportuna.

Principio de alta observabilidade (HOP)

O principio de alta observabilidade é un dos principios para o deseño de aplicacións en contenedores. Nunha arquitectura de microservizos, aos servizos non lles importa como se procesa a súa solicitude (e con razón), pero o importante é como reciben as respostas dos servizos receptores. Por exemplo, para autenticar un usuario, un contedor envía unha solicitude HTTP a outro, esperando unha resposta nun formato determinado, iso é todo. PythonJS tamén pode procesar a solicitude e Python Flask pode responder. Os contedores son como caixas negras con contidos ocultos entre si. Non obstante, o principio NOP require que cada servizo expoña varios puntos finais da API que indican o seu estado de saúde, así como o seu estado de preparación e tolerancia a fallos. Kubernetes solicita estes indicadores para pensar nos próximos pasos para o enrutamento e o equilibrio de carga.

Unha aplicación na nube ben deseñada rexistra os seus eventos principais usando os fluxos de E/S estándar STDERR e STDOUT. A continuación vén un servizo auxiliar, por exemplo filebeat, logstash ou fluentd, que entrega rexistros a un sistema de monitorización centralizado (por exemplo, Prometheus) e a un sistema de recollida de rexistros (paquete de software ELK). O seguinte diagrama mostra como funciona unha aplicación na nube segundo o patrón de proba de saúde e o principio de alta observabilidade.

Mellores prácticas para contedores Kubernetes: comprobacións de saúde

Como aplicar o patrón de comprobación de saúde en Kubernetes?

Fóra da caixa, k8s supervisa o estado dos pods usando un dos controladores (Implantacións, Conxuntos de réplicas, DaemonSets, StatefulSets etc., etc.). Despois de descubrir que o pod caeu por algún motivo, o controlador tenta reinicialo ou movelo a outro nodo. Non obstante, un pod pode informar de que está en funcionamento, pero non funciona. Poñamos un exemplo: a túa aplicación usa Apache como servidor web, instalaches o compoñente en varios pods do clúster. Dado que a biblioteca foi configurada incorrectamente, todas as solicitudes á aplicación responden co código 500 (erro interno do servidor). Ao comprobar a entrega, comprobar o estado das vainas dá un resultado exitoso, pero os clientes pensan doutro xeito. Describiremos esta situación indesexable do seguinte xeito:

Mellores prácticas para contedores Kubernetes: comprobacións de saúde

No noso exemplo, k8s faino comprobación da funcionalidade. Neste tipo de verificación, o kubelet comproba continuamente o estado do proceso no contedor. Unha vez que entenda que o proceso se detivo, reiniciao. Se o erro se pode resolver simplemente reiniciando a aplicación e o programa está deseñado para pecharse en caso de erro, só necesitas unha comprobación de estado do proceso para seguir o NOP e o Patrón de proba de saúde. A única mágoa é que non todos os erros se eliminan reiniciando. Neste caso, k8s ofrece dúas formas máis profundas de identificar problemas coa pod: LivenessProbe и ReadinessProbe.

LivenessProbe

Durante o LivenessProbe kubelet realiza 3 tipos de comprobacións: non só determina se o pod está funcionando, senón tamén se está listo para recibir e responder adecuadamente ás solicitudes:

  • Configura unha solicitude HTTP para o pod. A resposta debe conter un código de resposta HTTP no intervalo de 200 a 399. Así, os códigos 5xx e 4xx indican que o pod está a ter problemas, aínda que o proceso estea en execución.
  • Para probar pods con servizos non HTTP (por exemplo, o servidor de correo Postfix), cómpre establecer unha conexión TCP.
  • Executar un comando arbitrario para un pod (internamente). A comprobación considérase exitosa se o código de finalización do comando é 0.

Un exemplo de como funciona isto. A seguinte definición de pod contén unha aplicación NodeJS que xera un erro 500 nas solicitudes HTTP. Para asegurarnos de que o contedor se reinicia ao recibir tal erro, usamos o parámetro 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

Esta non é diferente de calquera outra definición de pod, pero estamos engadindo un obxecto .spec.containers.livenessProbe... Parámetro httpGet acepta o camiño ao que se envía a solicitude HTTP GET (no noso exemplo é /, pero en escenarios de combate pode haber algo así /api/v1/status). Outro livenessProbe acepta un parámetro initialDelaySeconds, que indica á operación de verificación que agarde un número especificado de segundos. O atraso é necesario porque o contedor necesita tempo para comezar e, cando se reinicie, non estará dispoñible durante algún tempo.

Para aplicar esta configuración a un clúster, use:

kubectl apply -f pod.yaml

Despois duns segundos, pode comprobar o contido do pod usando o seguinte comando:

kubectl describe pods node500

Ao final da saída, atopar iso é o que.

Como podes ver, livenessProbe iniciou unha solicitude HTTP GET, o contedor xerou un erro 500 (que é o que foi programado para facer) e o kubelet reiniciouno.

Se estás a preguntar como foi programada a aplicación NideJS, aquí tes o app.js e o Dockerfile que se usaron:

aplicación.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" ]

É importante ter en conta isto: livenessProbe só reiniciará o contenedor se falla. Se un reinicio non corrixe o erro que impide que o contedor se execute, o kubelet non poderá tomar medidas para corrixir o problema.

ReadinessProbe

readinessProbe funciona de forma similar a livenessProbes (solicitudes GET, comunicacións TCP e execución de comandos), excepto para as accións de resolución de problemas. O contedor no que se detecta o fallo non se reinicia, senón que está illado do tráfico entrante. Imaxina que un dos contedores está a realizar moitos cálculos ou está sometido a unha gran carga, o que fai que os tempos de resposta aumenten. No caso de livenessProbe, desenvólvese a verificación da dispoñibilidade de respostas (a través do parámetro de verificación timeoutSeconds), despois do cal o kubelet reinicia o contedor. Cando se inicia, o contedor comeza a realizar tarefas de uso intensivo de recursos e reiniciarase de novo. Isto pode ser crítico para aplicacións que precisan velocidade de resposta. Por exemplo, un coche mentres está na estrada está esperando unha resposta do servidor, a resposta retrasa e o coche ten un accidente.

Escribamos unha definición de redinessProbe que establecerá o tempo de resposta da solicitude GET en non máis de dous segundos e a aplicación responderá á solicitude GET despois de 5 segundos. O ficheiro pod.yaml debería verse así:

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

Imos implementar un pod con kubectl:

kubectl apply -f pod.yaml

Agardemos un par de segundos e despois vexamos como funcionou a ReadinessProbe:

kubectl describe pods nodedelayed

Ao final da saída podes ver que algúns dos eventos son similares este.

Como podes ver, kubectl non reiniciou o pod cando o tempo de verificación superou os 2 segundos. Pola contra, cancelou a solicitude. As comunicacións entrantes rediríxense a outros módulos que funcionen.

Teña en conta que agora que o pod está descargado, kubectl envía as solicitudes a el de novo: as respostas ás solicitudes GET xa non se atrasan.

Para comparar, a continuación móstrase o ficheiro app.js modificado:

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, RD
Antes da aparición das aplicacións na nube, os rexistros eran o principal medio para supervisar e comprobar o estado das aplicacións. Non obstante, non había medios para tomar ningunha medida correctora. Os rexistros aínda son útiles hoxe en día; é necesario recollelos e enviarlos a un sistema de recollida de rexistros para analizar situacións de emerxencia e tomar decisións. [Todo isto podería facerse sen aplicacións na nube que usasen monit, por exemplo, pero con k8s fíxose moito máis fácil :) - nota do editor. ]

Hoxe, as correccións teñen que facerse case en tempo real, polo que as aplicacións xa non teñen que ser caixas negras. Non, deberían mostrar puntos finais que permitan aos sistemas de monitorización consultar e recoller datos valiosos sobre o estado dos procesos para que poidan responder ao instante se é necesario. Isto chámase Patrón de deseño de probas de rendemento, que segue o Principio de alta observabilidade (HOP).

Kubernetes ofrece 2 tipos de comprobacións de estado por defecto: ReadinessProbe e LivenessProbe. Ambos usan os mesmos tipos de comprobacións (solicitudes HTTP GET, comunicacións TCP e execución de comandos). Diferéncianse nas decisións que toman en resposta aos problemas nas vainas. livenessProbe reinicia o contedor coa esperanza de que o erro non volva ocorrer e ReadinessProbe illa o pod do tráfico entrante ata que se resolva a causa do problema.

O deseño adecuado da aplicación debe incluír ambos tipos de comprobación e garantir que recollen datos suficientes, especialmente cando se lanza unha excepción. Tamén debería mostrar os puntos finais da API necesarios que proporcionan ao sistema de monitorización (Prometheus) importantes métricas de saúde.

Fonte: www.habr.com

Engadir un comentario