Contenedores sanos en la nube Cloud

Cuál es la clave para mantener los contenedores sanos en la nube ☁️

24/01/23 11 min. de lectura

¿Has pensado alguna vez cómo hacen los grandes para dar un servicio continuo en la nube si no paran de subir versiones de su software? 🤔 (Banco Santander somos uno de ellos con nuestra Cloud híbrida).

¿Cómo se consigue que nuestros clientes puedan acceder sin interrupciones con una mejora continua?

¿Cómo se sigue dando servicio si falla algún contenedor?

¿Quién vigila que todo esté levantado y funcionando?

Si te preguntas esto, aparte de leer cómo hacer despliegues complejos sin pérdida de servicio, sigue leyendo y sabrás 👇👇 :

  • Cuál es su secreto.
  • Cómo aplicarlo en tu Openshift o tu Kubernettes (incluso en tu kubernettes local).
  • Y hacerlo para servicios con un simple servidor http o un servicio más complejo.

¿Cuál es la clave?: ¡Comprobar que funciona!

Para que algo funcione no hay nada tan sencillo como comprobar periódicamente que está funcionando😊

Parece trivial, pero realmente sólo se puede dar servicio si el software está disponible para ser usado, es decir, el contenedor donde se ejecuta funciona correctamente.

Pero, ¿cómo consigues verificar que todos tus contenedores están funcionando?

¡Muy sencillo! Con Liveness probe y Readiness probe.

¿Qué es el Liveness probe?

Los gestores de contenedores son capaces de comprobar cada cierto tiempo si los contenedores están “vivos”, es decir, se puede ejecutar una prueba para comprobar que responden correctamente, e incluso, si sus dependencias también responden adecuadamente.

Esto se puede automatizar y que el gestor de contenedores realice acciones en caso de que no responda o responda que algo no va bien, y en ese caso, por ejemplo, reiniciar el contenedor que está fallando. Esa es la liveness probe.

¿Qué es la Readiness probe?

En cuanto a la readiness probe, puede ser la misma prueba, pero sirve para saber si el contenedor ya está levantado, es decir, ya puede dar servicio y ser usado.

¿Cuándo se usa eso? 🤷 🤷‍♂️

Pues, por ejemplo, cuando se despliega una nueva versión.

Hasta que la nueva versión no está «ready» no se permite que comience a dar servicio, y por supuesto, no se comienzan a destruir las versiones anteriores.

En Santander Digital Services se usa ampliamente de forma que no entre en producción una versión del software que no arranque correctamente, así como una vez funcionando, en caso de bloqueo, pueda recuperarse rápidamente ese servicio.

¿Y qué devuelve una liveness/readiness probe?

Pues puede dar más o menos detalle. Puede ser simplemente que un comando de consola devuelva un “exit 0” o bien un JSON con información completa del estado del contenedor y sus dependencias, y con un simple “UP” o con mucha más información, según se necesite.

Normalmente con el “UP” ya podemos determinar si funciona correctamente o no y actuar en consecuencia.

Estos son algunos ejemplos de una prueba readiness HTTP:

  • Sólo si está levantado por ejemplo, usuarios sin autenticar:

{«status»: «UP»}

  • Con detalle de los componentes:

{
«status»: «UP»,
«components»: {
«diskSpace»: {
«status»: «UP»
},
«livenessState»: {
«status»: «UP»
},
«mongo»: {
«status»: «UP»
},
«ping»: {
«status»: «UP»
},
«readinessState»: {
«status»: «UP»
},
«refreshScope»: {
«status»: «UP»
}
},
«groups»: [«liveness», «readiness»]
}

¿Cómo se configura el gestor de contenedores?

Pues según el gestor de contenedores y cómo queremos que éste lo compruebe, se define en la configuración del deploy de dicho contenedor.

Una de las formas más sencillas suele ser por verificación mediante una llamada HTTP, pero también, como hemos dicho, puede ser la salida de un comando o cualquier otra comprobación.

Como se podrá comprobar en los ejemplos, es posible configurar:

  • Cuánto esperamos para realizar la primera prueba
  • Cuánto tiempo esperaremos a que responda
  • Cada cuánto vamos a realizar la prueba
  • Cuántas veces seguidas ha de fallar para considerarlo un fallo real (puede fallar puntualmente por un pico de CPU por ejemplo)
  • Cuántas veces funciona bien para restaurar su estado de “funciona correctamente”

A continuación mostramos ejemplos de la configuración del contenedor para la verificación tanto liveness como readiness en los gestores de contenedores más usados, Openshift y Kubernetes.

En Santander Digital Services disponemos de ambas infraestructuras y así las usamos:

Openshift

containers:
  readinessProbe:
    httpGet:
      path: /actuator/health
      port: 8080
      scheme: HTTP
    initialDelaySeconds: 150
    timeoutSeconds: 10
    periodSeconds: 30
    successThreshold: 1
    failureThreshold: 3
  livenessProbe:
    httpGet:
      path: /actuator/health
      port: 8080
      scheme: HTTP
    initialDelaySeconds: 200
    timeoutSeconds: 10
    periodSeconds: 30
    successThreshold: 1
    failureThreshold: 3

En la documentación de Openshift (en inglés) se pueden otros muchos ejemplos.

Kubernetes

La configuración es prácticamente idéntica, en este caso el ejemplo que mostramos es la comprobación de la existencia de un fichero (implica que ejecuta el comando y dicho fichero puede ser leído).

containers:
  - name: liveness
[…]
    livenessProbe:
      exec:
        command:
          - cat
          - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

En la documentación de Kubernetes (en inglés) se pueden ver más ejemplos y configuraciones.

¿Cómo puedo preparar mi contenedor para ello? 🧐

El gestor de contenidos consultará algo de nuestro contenedor (un comando, un puerto TCP, el resultado de una petición HTTP) por lo que por nuestra parte debemos preparar nuestro software o nuestro contenedor para que responda cuando le pregunten.

Puede hacerse en el propio contenedor, al crearlo, disponer de un comando al final que genere por ejemplo un fichero (como en el ejemplo anterior), de forma que cuando el contenedor esté activo dicho fichero esté disponible.

Por ejemplo, para ajustarlo al ejemplo anterior de Kubernetes, en el fichero Docker podemos crear el fichero:

spec:
  containers:
    - name: liveness
      image: registry.k8s.io/busybox
      args:
        - /bin/sh
        - -c
        - touch /tmp/healthy

O también se puede crear un fichero .html con el “UP” que espera recibir la petición HTTP (y luego se verificará preguntando por /healthy.html)

spec:
  containers:
    - name: liveness
      image: nginx:latest
      args:
        - /bin/sh
        - -c
        - echo '{"status": "UP"}' > /usr/share/nginx/html/healthy.html

¿Y si sólo tengo imágenes precreadas? 🤔

En el caso que no podamos crear nuestro propio contenedor (por restricciones de nuestra empresa, por ejemplo), siempre podemos crear nuestro health check en nuestro software.

En Santander Digital Services para maximizar la seguridad de los contenedores usamos esta opción.

Siempre se puede configurar el gestor de contenedores para verificar que el puerto mediante el cual damos servicio está respondiendo, pero si queremos algo más, podemos responder con un fichero de health check algo más elaborado.

A continuación, mostramos algunos ejemplos en varios casos y son los que usamos en Santander Digital Services para asegurar el buen funcionamiento de nuestros contenedores…

Servidor web (Netty/Apache sirviendo HTML, Angular, React, Vue…)

Es tan sencillo como crear algún fichero .html con este sencillo contenido.

health.html:

{"status": "UP"}

De forma que si se pide /health.html se puede verificar que el servicio está levantado y sirve los ficheros.

Java Springboot

Si disponemos de un desarrollo Springboot, tenemos suerte porque simplemente con añadir la dependencia actuator ya tendríamos un endpoint para nuestro health.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Dicha dependencia permite muchas más cosas que simplemente el health aunque aquí nos centraremos en dicha funcionalidad.

El endpoint por defecto para la verificación es /actuator/health. Ejemplo de configuración del gestor de contenedores:

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
    scheme: HTTP

Dicha dependencia se puede configurar, de forma que podemos cambiarle el nombre del endpoint, por ejemplo, esta configuración cambia el path a /vrfy/health y sólo expone el endpoint de health, además de forma restrictiva, con la menor información posible:

management:
  context-path: /vrfy #cambiar el endpoint a /vrfy/health para que no sea el de por defecto
  security:
    enabled: true
  endpoints:
    web:
      base-path: /vrfy #cambiar el endpoint a /vrfy/health para que no sea el de por defecto
      exposure:
        include: 'health' # Solo habilito health
    health:
      sensitive: false #no quiero que muestre los detalles.
  endpoint:
    health:
      show-details: never #no quiero que muestre los detalles.

Cualquier otro software

En cualquier otro tipo de sofware podemos crear un endpoint HTTP para responder (y que responda como se hace desde Java en el punto anterior), o puerto TCP, registro en BBDD que se consulte desde el micro o cualquier otra forma que permita saber al gestor de contenedores que el microservicio sigue “vivo”.

¿Cuándo se mata mi proceso? 👇👇

Según como hayamos configurado el gestor de contenedores (número de intentos, timeout…), cuando se cumplan las condiciones, el gestor de contenedores destruirá el contenedor y creará uno nuevo.

En caso de que eso ocurra se ha de revisar los eventos, que suelen identificar que el health ha fallado y el número de veces.

Hay que tener en cuenta que por ejemplo, si así se ha configurado, puede ser que lo que esté caída es una dependencia del POD (por ejemplo, la BBDD o se ha quedado sin espacio) y eso generar un status caído.

Ejemplo de POD caído por dependencia:

$ curl http://127.0.0.1:8080/actuator/health

{	
  "status": "DOWN",
  "components": {
    "diskSpace": {
      "status": "UP",
    },
    "livenessState": {
      "status": "UP"
    },
    "mongo": {
      "status": "DOWN",
    },
    "ping": {
      "status": "UP"
    },
    "readinessState": {
      "status": "UP"
    },
    "refreshScope": {
      "status": "UP"
    }
  },
  "groups": ["liveness",   "readiness"]
}

¿Para qué más se puede usar los liveness probe?

¡Se puede usar para más cosas! 🙌

Por ejemplo, si disponemos de varios clusters (de openshift o varios kubernettes) donde se ejecutan nuestros contenedores, normalmente se dispone de un balanceador delante para balancear la carga.

Se puede configurar el balanceador de forma que verifique si los servicios de cada cluster están funcionando, y si por cualquier razón éstos no responden, es decir, no darían servicio, no manden tráfico hacia ese cluster.

En Santander Digital Services usamos esta capacidad de los balanceadores para evitar tráfico a un cluster que no va a devolver resultados y evitar errores innecesarios.

También puede ser usado, en caso de que las métricas que ofrezca sean detalladas, para comprobar o analizar las cargas de los contenedores en tiempo real (disco, memoria, cpu…).

Para terminar 👐

Tanto como si lo queremos para que nuestro servicio no pierda disponibilidad mientras desplegamos nuevas versiones como para que se reinicien en caso de dejar de darlo, tanto el liveness probe como el readiness probe nos permite que nuestra nube esté sana mediante el health de nuestros contenedores.

En Santander Digital Services es una de las formas que tenemos para hacer que no se pierda disponibilidad de nuestros servicios en la nube.

Santander Digital Services es una compañía del Grupo Santander con más de 7.000 empleados y basada en Madrid. Trabajamos para convertir al Santander en un banco digital con sucursales.

Mira las posiciones que tenemos abiertas aquí para unirte a este equipazo y Be Tech! with Santander 🚀

Síguenos en LinkedIn y en Instagram.

Ruben Rodríguez Martín

Rubén Rodríguez Martín

Santander

Ingeniero Informático que lleva programando desde los 10 años, usuario y administrador en internet desde el 96, especialista en desarrollo del software, sistemas, redes, seguridad, domótica, despliegues complejos, PaaS… y un gran aficionado a las nuevas tecnologías, optimizar procesos, la innovación, la ciencia ficción ¡y mucho más!

👉 Mi perfil de LinkedIn

 

Otros posts