Las verificaciones de disponibilidad en Kubernetes pueden ser peligrosas

Nota de traducción.: El ingeniero jefe de la compañía Zalando, Henning Jacobs, ha notado repetidamente que los usuarios de Kubernetes enfrentan problemas para entender el propósito de los liveness (y readiness) probes y su correcta aplicación. Por ello, ha recopilado sus pensamientos en esta concisa nota, que con el tiempo se convertirá en parte de la documentación de K8s.

Las verificaciones de disponibilidad en Kubernetes pueden ser peligrosas

Las verificaciones de estado, conocidas en Kubernetes como liveness probes (es decir, literalmente, “pruebas de viabilidad” - nota del traductor), pueden ser bastante peligrosas. Recomiendo evitarlas siempre que sea posible; las únicas excepciones son aquellos casos en que realmente son necesarias y usted comprende completamente la especificidad y las consecuencias de su uso. En esta publicación se tratará sobre las verificaciones de liveness y readiness, así como se explicará cuándo debe y no debe aplicarlas.

Un colega mío, Sandor, compartió recientemente en Twitter los errores más comunes que encuentra, incluidos los relacionados con el uso de readiness/liveness probes:

Las verificaciones de disponibilidad en Kubernetes pueden ser peligrosas

Una livenessProbe mal configurada puede empeorar situaciones de alta carga (una caída en cascada + un posible inicio prolongado del contenedor/aplicación) y llevar a otras consecuencias negativas, como la caída de dependencias. (ver también mi reciente artículo sobre la limitación del número de solicitudes en la combinación K3s+ACME). Peor aún, cuando el liveness probe se combina con la verificación de la salud de la dependencia (health check), que es una base de datos externa: una única falla en la base de datos reiniciará todos sus contenedores.!

El mensaje general “No use liveness probes” en este caso ayuda poco, así que examinemos para qué se utilizan las verificaciones de readiness y liveness.

Nota: La mayor parte de la prueba a continuación fue inicialmente incluida en la documentación interna para desarrolladores de Zalando.

Verificaciones de Readiness y Liveness

Kubernetes ofrece dos mecanismos importantes, llamados liveness probes y readiness probes. Estos realizan periódicamente alguna acción, como enviar una solicitud HTTP, abrir una conexión TCP o ejecutar un comando en el contenedor, para confirmar que la aplicación está funcionando correctamente.

Kubernetes utiliza readiness probes, para entender cuándo un contenedor está listo para recibir tráfico. Un pod se considera listo para funcionar si todos sus contenedores están listos. Una de las aplicaciones de este mecanismo es controlar qué pods se utilizan como backend para los servicios de Kubernetes (y especialmente para Ingress).

Sondeos de liveness ayudan a Kubernetes a entender cuándo es el momento de reiniciar un contenedor. Por ejemplo, esta verificación permite interceptar un bloqueo, cuando una aplicación 'se queda atascada' en un lugar. Reiniciar el contenedor en tal estado ayuda a mover la aplicación desde un punto muerto, a pesar de los errores, pero también puede llevar a fallos en cascada (ver más abajo).

Si intentas desplegar una actualización de la aplicación que falla en las verificaciones de liveness/readiness, su implementación se detendrá, ya que Kubernetes esperará el estado Listo de todos los pods.

Ejemplo

Aquí hay un ejemplo de un sondeo de readiness que verifica la ruta /health a través de HTTP con configuraciones por defecto (intervalo: 10 segundos, timeout: 1 segundo, umbral de éxito: 1, umbral de fallo: 3):

# часть общего описания deployment'а/стека
podTemplate:
  spec:
    containers:
    - name: my-container
      # ...
      readinessProbe:
        httpGet:
          path: /health
          port: 8080

Recomendaciones

  1. Para microservicios con un endpoint HTTP (REST, etc.) siempre define un sondeo de readiness, que verifica si la aplicación (pod) está lista para recibir tráfico.
  2. Asegúrate de que el sondeo de readiness cubra la disponibilidad del puerto real del servidor web:
    • usando puertos para necesidades administrativas, llamados 'admin' o 'management' (por ejemplo, 9090), para readinessProbe, asegúrate de que el endpoint devuelva OK solo si el puerto HTTP principal (como el 8080) está listo para recibir tráfico*;

      * Conozco al menos un caso en Zalando donde esto no ocurrió, es decir, readinessProbe verificó el puerto de 'management', pero el servidor no comenzó a funcionar debido a problemas con la carga de la caché.

    • colocar un sondeo de readiness en un puerto separado puede llevar a que la sobrecarga en el puerto principal no se refleje en la verificación de salud (es decir, la piscina de hilos en el servidor está llena, pero la verificación de salud sigue mostrando que todo está bien).
  3. Asegúrate de que el sondeo de readiness incluya la inicialización/migración de la base de datos;
    • la forma más sencilla de lograrlo es acceder al servidor HTTP solo después de que se haya completado la inicialización (por ejemplo, migración de base de datos con Flyway etc.); es decir, en lugar de cambiar el estado de la verificación de salud, simplemente no inicies el servidor web hasta que se complete la migración de la base de datos*.

      * También se pueden ejecutar migraciones de BD desde contenedores init fuera del pod. Sigo siendo un fanático de las aplicaciones autónomas (self-contained), es decir, aquellas en las que el contenedor de la aplicación sabe cómo llevar la BD al estado deseado sin coordinación externa.

  4. desde cualquier lugar del mundo. Es la solución ideal para crear una oficina en la nube, donde todos los programas y datos de los empleados están en un entorno seguro httpGet para las verificaciones de readiness a través de endpoints típicos de health checks (por ejemplo, /health).
  5. Infórmese sobre los parámetros de las comprobaciones configurados por defecto (interval: 10s, timeout: 1s, successThreshold: 1, failureThreshold: 3):
    • los parámetros por defecto significan que el pod estará not-ready aproximadamente después de 30 segundos (3 comprobaciones de salud fallidas).
  6. Utilice un puerto separado para «admin» o «management», si la pila tecnológica (por ejemplo, Java/Spring) lo permite, para separar la gestión de la «salud» y métricas del tráfico habitual:
    • pero no olvide el punto 2.
  7. Si es necesario, la readiness probe se puede utilizar para calentar/cargar la caché y devolver un código de estado 503 mientras el contenedor no esté «calentado»:

Advertencias

  1. No confíe en las dependencias externas (como los almacenes de datos) al ejecutar pruebas de readiness/liveness, ya que esto puede llevar a fallos en cascada:
    • tomemos como ejemplo un servicio stateful REST con 10 pods que dependen de una sola base de datos Postgres: cuando la verificación depende de una conexión activa a la BD, todos los 10 pods pueden caer si hay una latencia en la red/o en la BD, lo que normalmente termina peor de lo que podría haber sido;
    • tenga en cuenta que Spring Data por defecto verifica la conexión con la BD*;

      * Este es el comportamiento predeterminado de Spring Data Redis (al menos, lo era la última vez que lo comprobé), lo que llevó a una falla «catastrófica»: cuando Redis estuvo no disponible por un breve período, todos los pods «cayeron».

    • «externo» en este sentido también puede significar otros pods de la misma aplicación, es decir, idealmente la verificación no debería depender del estado de otros pods del mismo clúster para evitar caídas en cascada:
      • los resultados pueden variar para aplicaciones con estado distribuido (por ejemplo, almacenamiento en caché en memoria en los pods).
  2. No use liveness probe para los pods (excepciones son los casos en que realmente son necesarios y usted comprende completamente la especificidad y las consecuencias de su uso):
    • el liveness probe puede ayudar a recuperar contenedores "atrapados", pero, dado que tiene el control total sobre su aplicación, tales cosas como procesos "atrapados" y deadlocks no deberían ocurrir idealmente: la mejor alternativa es causar la caída intencional de la aplicación y devolverla a un estado estable anterior;
    • un liveness probe fallido llevará a un reinicio del contenedor, potencialmente agravando las consecuencias de errores relacionados con la carga: el reinicio del contenedor provocará inactividad (al menos, durante el tiempo de inicio de la aplicación, digamos, más de 30 segundos), causando nuevos errores, aumentando la carga en otros contenedores y aumentando la probabilidad de que fallen, etc.;
    • las liveness checks combinadas con una dependencia externa son la peor de las combinaciones posibles, amenazando con fallos en cascada: ¡un pequeño retraso del lado de la base de datos llevará al reinicio de todos sus contenedores!
  3. Los parámetros de las liveness y readiness checks deben ser diferentes:
    • se puede utilizar un liveness probe con la misma verificación de estado, pero con un umbral de activación más alto (failureThreshold), por ejemplo, asignar el estado not-ready después de 3 intentos y considerar que el liveness probe ha fallado después de 10 intentos;
  4. No use verificaciones exec, ya que están asociadas con problemas conocidos que conducen a la aparición de procesos huérfanos:

Currículum

  • Utilice readiness probes para determinar cuándo el pod está listo para recibir tráfico.
  • Utilice liveness probes solo cuando realmente sean necesarios.
  • El uso incorrecto de readiness/liveness probes puede llevar a una disminución de la disponibilidad y fallos en cascada.

Las verificaciones de disponibilidad en Kubernetes pueden ser peligrosas

Material adicional sobre el tema

Actualización #1 del 2019-09-29

Sobre init-containers para la migración de bases de datos: se agregó una nota al pie.

EJ me recordó sobre PDB: uno de los problemas de las liveness checks es la falta de coordinación entre los pods. En Kubernetes hay Pod Disruption Budgets (PDB) para limitar el número de fallos paralelos que una aplicación puede experimentar, pero las verificaciones no tienen en cuenta PDB. Idealmente, podemos ordenar a K8s: «Reinicia un pod si su verificación falla, pero no los reinicies todos para no empeorar la situación».

Bryan lo expresó muy bien: «Utiliza sondas de liveness cuando sepas con certeza que lo mejor que se puede hacer es “matar” la aplicación» (una vez más, no hay que exagerar).

Las verificaciones de disponibilidad en Kubernetes pueden ser peligrosas

Actualización nº 2 del 2019-09-29

Respecto a leer la documentación antes de usar: creé una solicitud pertinente (feature request) para añadir documentación sobre las sondas de liveness.

P.D. del traductor

También puedes leer en nuestro blog:

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster