688 - Tu contenedor Docker podría estar muerto y tu sin enterarte

688 - Tu contenedor Docker podría estar muerto y tu sin enterarte

el #healthcheck es una característica de #docker para conocer la salud de un servicio, porque tu contenedor puede estar corriendo y el servicio muerto

1:25
-3:15

Este es un tema que tendría que haber abordado hace mucho tiempo, pero que, como en otras cosas de la vida, vas dejando. Y al igual que sucede en la vida, no es que este tema no sea importante, que lo es, sino que lo vas dejando, porque como no pasa nada, pero ¿y cuando pasa?, entonces nos lamentamos. Como te decía, es lo mismo que sucede en la vida real con la salud, mientras tienes saludo, porque te tienes que cuidar, pero cuando llegan los problemas, es cuando nos comenzamos a preocupar. En este caso, no ha sido directamente por un problema con el que me he tropezado, si no por una molestia, de la que te he hablado en otras ocasiones, y que puede ser que haya encontrado una solución. Y todo ello gracías al Health Check de Docker. Una característica que nos ofrece Docker y que nos permite conocer la salud de nuestros contenedores. Por que si, un contenedor puede estar running pero el proceso muerto, y como te digo, tu sin enterarte.

Tu contenedor Docker podría estar muerto y tu sin enterarte

Un paseo por el pasado

Hace ya algún tiempo, que al actualizar, de forma automática las imágenes que componen el stack de atareao.es, todos los contenedores no arrancan de forma adecuada y me quedo sin la página durante unas horas. Para minimizar este proyecto, lo que hice, fue, que esta actualización se hiciera una vez a la semana, pero como te puedes imaginar, esto no es una solución, es un parche.

Posteriormente, añadí dependencias, para que asegurar que cuando se levanta WordPress, ya esté levantada la base de datos y Redis. Sin embargo, esto no es suficiente, porque si bien MariaDB, está iniciado, todavía no está preparada para recibir peticiones. Entiendo o supongo que es precisamente, este punto donde se queda el proceso y no continua.

Hasta hace poco esto lo tenía de la siguiente manera,

depends:
- mariadb
- redis

De forma que mi servicio WordPress dependía de estos dos servicios. Con esto yo pensaba que estaba todo resuelto, pero no es tanto así, porque aunque la base de datos esté levantada puede ser que no esté disponible para recibir peticiones, como te decía anteriormente. Y aquí justo es donde aparece el Health Check de Docker.

Docker Health Check

Pero, antes que nada, ¿que es esto del Health Check de Docker? En la documentación oficial de Docker, dice que el Health Check es una forma de comprobar si un contenedor está funcionando correctamente. Esto se hace mediante un comando que se ejecuta dentro del contenedor y que devuelve un estado de salud. Este estado puede ser healthy, unhealthy o starting. De esta forma, podemos saber si el contenedor está funcionando correctamente o no.

Básicamente se trata de pruebas que se ejecutan en el propio contenedor y que nos permite determinar si todo funciona como debería o no. Se trata de una capa mas sobre el estado del servicio. Sin embargo, te tengo que avisar de que no todos los contenedores lo tienen configurado por defecto. Aunque siempre tienes la posibilidad de configurarlo tu.

Esta característica es la que nos informa de que un contenedor está healthy o unhealthy. En el caso de que el contenedor esté unhealthy, Docker no lo va a reiniciar automáticamente, pero si lo puedes hacer tu. De esta forma, puedes configurar un servicio para que dependa de otro, pero no solo de que esté levantado, sino también de que esté funcionando correctamente.

Por ejemplo, en mi caso particular, la cuestión es que si bien el contenedor ya inició, lo cierto es que la base de datos está todavía en proceso. Con lo que todavía no está healthy. Así es posible que tengas un proceso running y unhealthy. Es posible ver este estado utilizando un simple docker ps, o mediante un docker inspect <nombre-del-contenedor>.

Configuración del Health Check

Existen dos formas principales de configurar un healthcheck, que es o bien en el propio Dockerfile o bien en el docker-compose.yml. Es decir, que en cualquier caso, siempre es posible definir tu propio healthcheck que te asegure que tu servicio esté funcionando de forma saludable.

Por ejemplo, en el Dockerfile podría ser de la siguiente forma,

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -f http://localhost:3000 || exit 1

Este ejemplo comprueba cada 30 segundos que la web en el puerto 3000 responde correctamente.

O bien en el docker-compose.yml, que es lo que yo he hecho en mi caso particular,

services:
  mi-api:
    image: miimagen
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000"]
      interval: 30s
      timeout: 5s
      retries: 3

El contenedor pasa por tres estados,

  • starting. Cuando está iniciando y aún no ha hecho suficientes checks
  • healthy. Cuando pasa los checks definidos
  • unhealthy. Si falla los checks el número de veces que hayas configurado

Algunos ejemplos

  • MariaDB
healthcheck:
    test: ["CMD", "mariadb-admin" ,"ping", "-h", "localhost", "--password=${DB_PASSWORD}"]
    start_period: 1m
    start_interval: 10s
    interval: 1m
    timeout: 5s
    retries: 3
  • Redis
healthcheck:
  test: [ "CMD", "redis-cli", "ping" ]
  start_period: 10s
  timeout: 5s
  retries: 3
  • Nginx
healthcheck:
  test: curl --fail http://localhost || exit 1
  interval: 60s
  retries: 5
  start_period: 20s
  timeout: 10s
  • Postgresql
healthcheck:
  test: ["CMD-SHELL", "sh -c 'pg_isready -U preemer -d preemer'"]
  interval: 10s
  timeout: 5s
  retries: 10

Algunos casos de uso

Te cuento algunos casos reales donde estoy usando healthchecks:

  • Aplicación web en Rust + React: tengo configurado un healthcheck que comprueba si la API responde y si el frontend devuelve el HTML esperado. Así me aseguro de que el backend y frontend están activos antes de permitir otras tareas programadas.
  • PostgreSQL: uso un script que intenta conectarse al puerto 5432 y ejecutar una simple consulta SQL. Esto evita iniciar otros contenedores que dependen de la base de datos hasta que realmente esté lista.
  • Tautulli y Plex: en casa tengo montado mi servidor multimedia con Docker. Si alguno de los servicios no está en estado healthy, envío una alerta vía Telegram usando un bot.
  • Backups automáticos con Restic y Gocron: antes de lanzar el backup, reviso que los contenedores de los que se va a hacer backup estén healthy. Si no, cancelo el backup y lo intento más tarde.

Combinando con las dependencias

Y todo esto ¿como casa con las dependencias? Justo aquí viene la parte que a mi mas me interesa, que es precisamente unir esto, para que WordPress no se inicie hasta que la base de datos esté funcionando perfectamente. Para ello, he modificado el depends de la siguiente forma,

depends_on:
  mariadb:
    condition: service_healthy
    restart: true
  redis:
    condition: service_healthy

Con estas opciones hasta que los dos servicios no estén iniciados y en modo saludable no se iniciará WordPress.

Conclusión

Tengo que decirte que si bien, lo tengo implementado todavía no he tenido la oportunidad de verificar si esto resuelve mis problemas o no. Desde luego, con las pruebas que he hecho hasta el momento todo pinta que si, pero, todavía tendrán que pasar unos días hasta que te lo pueda confirmar. Tampoco serán muchos días, porque en breve viene una actualización de WordPress.

Sea como fuere, esta características es una herramienta sencilla pero realmente potente para asegurarte que tus contenedores no solo están arrancados si no que además están vivos y coleando.

¿Tu utilizas esta característica de Docker?¿Donde la estás utilizando?¿Tienes otros casos de uso distintos?


Más información,

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *