Capítulo 4. Sonda sanitaria
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
El patrón Health Probe indica cómo una aplicación puede comunicar su estado de salud a Kubernetes. Para ser totalmente automatizable, una aplicación nativa de la nube debe ser altamente observable, permitiendo inferir su estado para que Kubernetes pueda detectar si la aplicación está levantada y si está lista para servir peticiones. Estas observaciones influyen en la gestión del ciclo de vida de los Pods y en la forma en que se enruta el tráfico hacia la aplicación.
Problema
Kubernetes comprueba regularmente el estado del proceso del contenedor y lo reinicia si detecta problemas. Sin embargo, por la práctica, sabemos que comprobar el estado del proceso no es suficiente para determinar la salud de una aplicación. En muchos casos, una aplicación se cuelga, pero su proceso sigue en marcha. Por ejemplo, una aplicación Java puede lanzar un OutOfMemoryError
y seguir teniendo el proceso JVM en ejecución. Otra posibilidad es que una aplicación se bloquee porque se encuentre con un bucle infinito, un punto muerto o algún thrashing (caché, montón, proceso). Para detectar este tipo de situaciones, Kubernetes necesita una forma fiable de comprobar la salud de las aplicaciones, es decir, no para entender cómo funciona internamente una aplicación, sino para comprobar si la aplicación funciona como se espera y es capaz de servir a los consumidores.
Solución
La industria del software ha aceptado el hecho de que no es posible escribir código libre de fallos. Además, las posibilidades de fallo aumentan aún más cuando se trabaja con aplicaciones distribuidas. En consecuencia, el enfoque para hacer frente a los fallos ha pasado de evitarlos a detectar los fallos y recuperarse. Detectar fallos no es una tarea sencilla que pueda realizarse uniformemente para todas las aplicaciones, ya que cada cual tiene definiciones distintas de un fallo. Además, los distintos tipos de fallos requieren acciones correctivas diferentes. Los fallos transitorios pueden autorrecuperarse, si se les da tiempo suficiente, y algunos otros fallos pueden necesitar un reinicio de la aplicación. Veamos las comprobaciones que utiliza Kubernetes para detectar y corregir los fallos.
Comprobaciones de la salud del proceso
Una comprobación del estado de los procesos es la comprobación de estado más sencilla que el Kubelet realiza constantemente en los procesos del contenedor. Si los procesos del contenedor no se están ejecutando, el contenedor se reinicia en el nodo al que está asignado el Pod. Por tanto, incluso sin ninguna otra comprobación de salud, la aplicación se vuelve ligeramente más robusta con esta comprobación genérica. Si tu aplicación es capaz de detectar cualquier tipo de fallo y cerrarse por sí misma, la comprobación del estado de los procesos es todo lo que necesitas. Sin embargo, para la mayoría de los casos, eso no es suficiente, y también son necesarios otros tipos de comprobaciones de salud.
Sondas de Lividez
Si tu aplicación entra en un punto muerto, sigue considerándose saludable desde el punto de vista de la comprobación de la salud del proceso. Para detectar este tipo de problema y cualquier otro tipo de fallo de acuerdo con la lógica de negocio de tu aplicación, Kubernetes dispone de sondas de vitalidad:comprobaciones periódicasrealizadas por el agente Kubelet que pide a tu contenedor que confirme que sigue sano. Es importante que la comprobación de salud se realice desde el exterior y no en la propia aplicación, ya que algunos fallos pueden impedir que el perro guardián de la aplicación informe de su fallo. En cuanto a la acción correctiva, esta comprobación de salud es similar a la comprobación de salud de un proceso, ya que si se detecta un fallo, se reinicia el contenedor. Sin embargo, ofrece más flexibilidad en cuanto a los métodos a utilizar para comprobar la salud de la aplicación, como se indica a continuación:
- Sonda HTTP
-
Realiza una petición HTTP GET a la dirección IP del contenedor y espera un código de respuesta HTTP correcto entre 200 y 399.
- Sonda de socket TCP
-
Supone una conexión TCP correcta.
- Sonda de ejecución
-
Ejecuta un comando arbitrario en el espacio de nombres del usuario y del núcleo del contenedor y espera un código de salida correcto (0).
- Sonda gRPC
-
Aprovecha el soporte intrínseco de gRPC para las comprobaciones de salud.
Además de la acción de la sonda, se puede influir en el comportamiento del chequeo con los siguientes parámetros:
initialDelaySeconds
-
Especifica el número de segundos que hay que esperar hasta que se compruebe la primera sonda de vitalidad.
periodSeconds
-
El intervalo en segundos entre las comprobaciones de la sonda de vida.
timeoutSeconds
-
El tiempo máximo permitido para que vuelva una comprobación de sonda antes de que se considere que ha fallado.
failureThreshold
-
Especifica cuántas veces seguidas debe fallar una comprobación de sonda hasta que se considere que el contenedor no está sano y debe reiniciarse.
En el Ejemplo 4-1 se muestra un ejemplo de sonda de caducidad basada en HTTP.
Ejemplo 4-1. Contenedor con sonda de vida
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
pod-with-liveness-check
spec
:
containers
:
-
image
:
k8spatterns/random-generator:1.0
name
:
random-generator
env
:
-
name
:
DELAY_STARTUP
value
:
"
20
"
ports
:
-
containerPort
:
8080
protocol
:
TCP
livenessProbe
:
httpGet
:
path
:
/actuator/health
port
:
8080
initialDelaySeconds
:
30
Según la naturaleza de tu aplicación, puedes elegir el método que más te convenga. Depende de tu aplicación decidir si se considera saludable o no. Sin embargo, ten en cuenta que el resultado de no pasar una comprobación de salud es que tu contenedor se reiniciará. Si reiniciar tu contenedor no ayuda, no hay ninguna ventaja en tener una comprobación de salud fallida, ya que Kubernetes reinicia tu contenedor sin solucionar el problema subyacente.
Sondas de preparación
Liveness las comprobaciones ayudan a mantener sanas las aplicaciones matando los contenedores no sanos y sustituyéndolos por otros nuevos. Pero a veces, cuando un contenedor no está sano, reiniciarlo puede no servir de nada. Un ejemplo típico es un contenedor que todavía se está iniciando y no está preparado para gestionar ninguna solicitud. Otro ejemplo es una aplicación que sigue esperando a que esté disponible una dependencia, como una base de datos. Además, un contenedor puede sobrecargarse, aumentando su latencia, por lo que querrás que se proteja de la carga adicional durante un tiempo e indique que no está listo hasta que la carga disminuya.
Para este tipo de escenario, Kubernetes dispone de sondas de disponibilidad. Los métodos (HTTP, TCP, Exec, gRPC) y las opciones de tiempo para realizar comprobaciones de disponibilidad son los mismos que para las comprobaciones de vida, pero la acción correctiva es diferente. En lugar de reiniciar el contenedor, una sonda de disponibilidad fallida hace que el contenedor se elimine del punto final del servicio y no reciba ningún tráfico nuevo. Las sondas de disponibilidad señalan cuándo un contenedor está preparado, de modo que tenga tiempo de calentarse antes de recibir peticiones del servicio. También es útil para proteger al contenedor del tráfico en etapas posteriores, ya que las sondas de preparación se realizan con regularidad, de forma similar a las comprobaciones de liveness. El Ejemplo 4-2 muestra cómo puede implementarse una sonda de disponibilidad comprobando la existencia de un archivo que la aplicación crea cuando está lista para operar.
Ejemplo 4-2. Contenedor con sonda de preparación
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
pod-with-readiness-check
spec
:
containers
:
-
image
:
k8spatterns/random-generator:1.0
name
:
random-generator
readinessProbe
:
exec
:
command
:
[
"
stat
"
,
"
/var/run/random-generator-ready
"
]
De nuevo, depende de tu implementación de la comprobación de estado decidir cuándo tu aplicación está preparada para hacer su trabajo y cuándo debe quedarse sola. Mientras que las comprobaciones de salud del proceso y las comprobaciones de liveness pretenden recuperarse del fallo reiniciando el contenedor, la comprobación de preparación gana tiempo para tu aplicación y espera que se recupere por sí misma. Ten en cuenta que Kubernetes intenta evitar que tu contenedor reciba nuevas peticiones (cuando se está apagando, por ejemplo), independientemente de si la comprobación de preparación sigue pasando después de haber recibido una señal SIGTERM.
En muchos casos, las sondas de liveness y readiness realizan las mismas comprobaciones. Sin embargo, la presencia de una sonda de preparación da tiempo a que tu contenedor se ponga en marcha. Sólo si se supera la comprobación de disponibilidad se considera que una Implementación se ha realizado correctamente, de modo que, por ejemplo, los Pods con una versión anterior puedan finalizar como parte de una actualización continua.
Para las aplicaciones que necesitan mucho tiempo para inicializarse, es probable que el fallo de las comprobaciones de vitalidad haga que tu contenedor se reinicie antes de que termine el arranque. Para evitar estos cierres no deseados, puedes utilizar sondas de arranque que indiquen cuándo ha terminado el arranque.
Sondas de arranque
Las sondas de caducidad también pueden utilizarse exclusivamente para permitir tiempos de arranque largos, alargando los intervalos de comprobación, aumentando el número de reintentos y añadiendo un retardo mayor para la comprobación inicial de la sonda de caducidad. Sin embargo, esta estrategia no es óptima, ya que estos parámetros de temporización también se aplicarán a la fase posterior al arranque e impedirán que tu aplicación se reinicie rápidamente cuando se produzcan errores fatales.
Cuando las aplicaciones tardan minutos en iniciarse (por ejemplo, los servidores de aplicaciones Jakarta EE), Kubernetes proporciona sondas de inicio.
Las sondas de arranque se configuran con el mismo formato que las sondas de caducidad, pero permiten valores distintos para la acción de la sonda y los parámetros de temporización. Los parámetros periodSeconds
y failureThreshold
se configuran con valores mucho mayores que los de las sondas de caducidad correspondientes, para tener en cuenta que el inicio de la aplicación es más largo. Las sondas de caducidad y preparación sólo se activan después de que la sonda de inicio informe de que ha tenido éxito. El contenedor se reinicia si la sonda de inicio no tiene éxito dentro del umbral de fallo configurado.
Aunque se puede utilizar la misma acción de sonda para las sondas de caducidad y de arranque, un arranque correcto suele indicarse mediante un archivo marcador cuya existencia comprueba la sonda de arranque.
El ejemplo 4-4 es un ejemplo típico de servidor de aplicaciones Jakarta EE que tarda mucho en iniciarse.
Ejemplo 4-4. Contenedor con sonda de arranque y vida útil
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
pod-with-startup-check
spec
:
containers
:
-
image
:
quay.io/wildfly/wildfly
name
:
wildfly
startupProbe
:
exec
:
command
:
[
"
stat
"
,
"
/opt/jboss/wildfly/standalone/tmp/startup-marker
"
]
initialDelaySeconds
:
60
periodSeconds
:
60
failureThreshold
:
15
livenessProbe
:
httpGet
:
path
:
/health
port
:
9990
periodSeconds
:
10
failureThreshold
:
3
Servidor JBoss WildFly Jakarta EE que tardará en iniciarse.
Archivo de marcador que crea WildFly tras un inicio correcto.
Parámetros de temporización que especifican que el contenedor debe reiniciarse cuando no ha pasado la sonda de inicio después de 15 minutos (pausa de 60 segundos hasta la primera comprobación, luego un máximo de 15 comprobaciones con intervalos de 60 segundos).
Los parámetros de tiempo para las sondas de caducidad son mucho menores, lo que provoca un reinicio si las sondas de caducidad posteriores fallan en 20 segundos (tres reintentos con pausas de 10 segundos entre cada uno).
Las sondas de liveness, readiness y startup son bloques fundamentales de la automatización de aplicaciones nativas de la nube. Los marcos de aplicaciones como Quarkus SmallRye Health, Spring Boot Actuator, WildFly Swarm health check, Apache Karaf health check, o la especificación MicroProfile para Java proporcionan implementaciones para ofrecer sondas de salud.
Debate
Para ser totalmente automatizables, las aplicaciones nativas de la nube deben ser altamente observables, proporcionando un medio para que la plataforma de gestión lea e interprete la salud de la aplicación y, si es necesario, tome medidas correctivas. Las comprobaciones de salud desempeñan un papel fundamental en la automatización de actividades como la implementación, la autorreparación y el escalado, entre otras. Sin embargo, también hay otros medios a través de los cuales tu aplicación puede proporcionar más visibilidad sobre su salud.
El método obvio y antiguo para este fin es mediante el registro. Es una buena práctica que los contenedores registren cualquier evento significativo de salida del sistema y error del sistema, y que estos registros se recopilen en una ubicación central para su posterior análisis. Los registros no suelen utilizarse para emprender acciones automatizadas, sino más bien para alertar e investigar más a fondo. Un aspecto más útil de los registros es el análisis postmortem de fallos y la detección de errores imperceptibles en.
Además de registrar en los flujos estándar, también es una buena práctica registrar el motivo por el que se sale de un contenedor en /dev/termination-log. Esta ubicación es el lugar donde el contenedor puede manifestar su última voluntad antes de desaparecer definitivamente.1 La Figura 4-1 muestra en las posibles opciones de cómo puede comunicarse un contenedor con la plataforma en tiempo de ejecución.
Los contenedores proporcionan una forma unificada de empaquetar y ejecutar aplicaciones, tratándolas como sistemas opacos. Sin embargo, cualquier contenedor que pretenda convertirse en un ciudadano nativo de la nube debe proporcionar API para que el entorno de ejecución observe la salud del contenedor y actúe en consecuencia. Este soporte es un requisito previo fundamental para automatizar las actualizaciones y el ciclo de vida del contenedor de forma unificada, lo que a su vez mejora la resistencia del sistema y la experiencia del usuario. En términos prácticos, eso significa que, como mínimo, tu aplicación en contenedores debe proporcionar APIs para los distintos tipos de comprobaciones de salud (liveness y readiness).
Las aplicaciones aún mejores también deben proporcionar otros medios para que la plataforma de gestión observe el estado de la aplicación en contenedores, integrándose con bibliotecas de rastreo y recopilación de métricas como OpenTracing o Prometheus. Trata tu aplicación como un sistema opaco, pero implementa todas las API necesarias para ayudar a la plataforma a observar y gestionar tu aplicación de la mejor manera posible.
El siguiente patrón, Ciclo de vida gestionado, también trata de la comunicación entre las aplicaciones y la capa de gestión de Kubernetes, pero desde la otra dirección. Se trata de cómo se informa a tu aplicación de los eventos importantes del ciclo de vida de Pod.
1 Alternativamente, puedes cambiar el campo .spec.containers.terminationMessagePolicy
de un Pod a FallbackToLogsOnError
, en cuyo caso la última línea del registro se utiliza para el mensaje de estado del Pod cuando termina.
Get Patrones Kubernetes, 2ª Edición now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.