Ir al contenido principal

Goss: Validación de servicios e integración con Docker

En esta guía, exploraremos en detalle qué es Goss, cómo se utiliza para validar y mantener el estado de salud de los servicios, y cómo puedes integrarlo fácilmente dentro de tus imágenes Docker. Para aquellos que buscan mejorar la calidad de sus desarrollos y despliegues, Goss se presenta como una solución confiable y eficiente.

¿Qué es Goss?

Goss es una herramienta de validación de servicios de infraestructura que se puede utilizar para verificar que un servicio de Docker está funcionando correctamente. Puede utilizar Goss para crear y ejecutar pruebas de integración en su servicio de Docker, lo que le permite asegurarse de que está configurado correctamente y está respondiendo como se espera. Goss es fácil de usar y se integra bien con Docker, lo que lo hace una excelente opción para validar servicios de Docker.

Usos de la herramienta Goss

Goss puede ser utilizado en Linux para validar una variedad de aspectos de la configuración y el comportamiento de los servicios. Algunos ejemplos de usos de Goss en Linux incluyen:

  • Validación de configuraciones de red: Goss puede utilizarse para verificar que los servicios de red, como DNS y DHCP, están configurados correctamente y respondiendo a las solicitudes.
  • Validación de configuraciones de seguridad: Goss puede utilizarse para verificar que las configuraciones de seguridad, como el firewall y el acceso SSH, están configuradas correctamente.
  • Validación de configuraciones de sistema: Goss puede utilizarse para verificar que los servicios de sistema, como la configuración de la memoria y el espacio en disco, están configuradas correctamente.
  • Validación de servicios de aplicaciones: Goss puede utilizarse para verificar que los servicios de aplicaciones, como un servidor web o una base de datos, están funcionando correctamente y respondiendo a las solicitudes.
  • Validación de configuraciones de monitoreo: Goss puede utilizarse para verificar que los servicios de monitoreo, como Zabbix o Nagios, están configuradas correctamente y recolectando los datos correctos.

Es importante tener en cuenta que estas son solo algunas de las posibles utilizaciones de Goss en Linux, ya que su flexibilidad le permite adaptarse a una amplia variedad de entornos y situaciones.

Instalación y validar servicio: Cómo validar con Goss

Vamos a ver un ejemplo de cómo validar con Goss, para ello seguimos los siguientes pasos generales:

  1. Instalar Goss: para hacer uso de Goss, primero necesitarás instalarlo en tu sistema Linux. Puedes hacerlo descargando el paquete binario desde la página de descargas de Goss o utilizando un administrador de paquetes como apt o yum.
  2. Crear las pruebas: Goss utiliza un lenguaje de script YAML para especificar las pruebas a realizar. Crea un archivo YAML con las pruebas que deseas realizar en tu servicio.
  3. Ejecutar las pruebas: utiliza el comando goss run para ejecutar las pruebas especificadas en el archivo YAML.
  4. Revisar los resultados: Goss presenta los resultados de las pruebas en un formato estandarizado. Si alguna prueba falla, se informará del error y se detallará el problema.

Ejemplo:

# Instalar Goss
curl -fsSL https://goss.rocks/install | sh

# Crear un archivo de pruebas para verificar que el servicio web está funcionando correctamente
echo "http:
  # Verificar que el servidor está respondiendo
  status: 200
  # Verificar que el servidor está respondiendo con el contenido esperado
  body: /Welcome to my website/" > test.yaml

# Ejecutar las pruebas
goss --gossfile test.yaml validate

En este ejemplo, se verifica que el servicio web está funcionando correctamente, respondiendo con un código de estado 200 y un contenido específico. Si la prueba falla, se informará del error.

Cómo configurar Goss en una imagen docker

Es posible utilizar Goss para validar servicios dentro de un contenedor Docker mediante la adición de las instrucciones necesarias para ejecutarlo en el archivo Dockerfile. Al hacerlo, se ejecutará automáticamente cada vez que se construya o inicie el contenedor.

Cambios en nuestro compose

Lo primero que vamos a hacer es cambiar la forma con la que nuestro docker-compose lee la imagen docker.

Esta es la forma normal de agregar imágenes a un servicio en docker, donde se descarga de los repositorios oficiales de docker.

version: "3"
services:
  odoo14:
    image: odoo:14.0
    ...

  nginx:
    image: nginx
    ...

  postgres-odoo:
    image: postgres:12.8
    ...

Lo cambiaremos para crear nuestra propia imagen para ello vamos a crear un archivo Dockerfile para cada servicio donde vamos a tener goss.

vagrant@master:~/odoo$ cat dockerfile/odoo14/Dockerfile 
FROM odoo:14.0

vagrant@master:~/odoo$ cat dockerfile/postgres-odoo/Dockerfile 
FROM postgres:12.8

vagrant@master:~/odoo$ cat dockerfile/nginx/Dockerfile 
FROM nginx

Con estos cambios construimos la imagen mediante el Dockerfile creado previamente, con esto conseguimos agregar más parámetros o mejoras.

Levantamos el docker-compose y ya tenemos los contenedores.

vagrant@master:~/odoo$ docker-compose ps
     Name                   Command               State                                   Ports                                 
--------------------------------------------------------------------------------------------------------------------------------
nginx            /docker-entrypoint.sh ngin ...   Up      0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0:80->80/tcp,:::80->80/tcp
odoo14           /entrypoint.sh odoo              Up      0.0.0.0:8069->8069/tcp,:::8069->8069/tcp, 8071/tcp, 8072/tcp          
portainer-odoo   /portainer                       Up      9000/tcp                                                              
postgres-odoo    docker-entrypoint.sh postgres    Up      0.0.0.0:5432->5432/tcp,:::5432->5432/tcp  

En la columna del estado vemos que está Up pero no sabemos si está Healthy o no, para ello vamos a configurar goss.

Agregamos goss

Para validar servicios, se deben crear archivos de prueba específicos para cada servicio que se desea validar. Estos archivos deben especificar los parámetros y comportamientos esperados del servicio, y Goss comparará estos parámetros con los valores reales del servicio para determinar si el servicio está funcionando correctamente.

¿Cómo lo vamos a configurar?

  • Nginx revisará si tiene abierto su propio puerto y también que estén todos los servicios activos, de lo contrario no iniciará el servicio.
  • Odoo comprueba si tiene activo su propio puerto y si responde la llamada a la web, luego va a revisar que tiene conexión con postgres y que puede acceder a la base de datos.
  • Postgres revisará solo si tiene abierto su propio puerto.

Las comprobaciones a sí mismo las podemos poner sobre el archivo, goss.yaml. Mientras que las comprobaciones hacia otros servicio lo agregaremos al archivo goss-command.yaml (Este nombre es orientativo y se puede cambiar)

Archivos Goss de Odoo

Este archivo verifica que esté escuchando en el puerto 8069 y hará una llamada a sí mismo este tiene que responder con un código de estado 200 para su correcto funcionamiento.

$ cat dockerfile/odoo/goss/goss.yaml

port:
  tcp:8069:
    listening: true

http:
  http://localhost:8069/web/database/selector:
    status: 200
    allow-insecure: false
    no-follow-redirects: false
    timeout: 5000
    body: []

Para el archivo goss-command.yaml, vamos a realizar pruebas para comprobar el funcionamiento de postgres. En primer lugar, si este responde al servicio y después si puede iniciar sesión dentro de la base de datos, para esta opción tenemos que tener instalado el cliente del gestor en la máquina.

$ cat dockerfile/odoo/goss/goss-command.yaml

addr:
  tcp://postgres-odoo:5432:
    reachable: true
    timeout: 500

command:
  PGPASSWORD=${MY_PASSWORD} psql -h postgres-odoo -U ${MY_USER} -d postgres:
    title: Ensure we have valid credentials
    exit-status: 0
    timeout: 50000 # 5s

Archivos goss de postgres

Postgres solamente va a comprobar si está abierto el puerto 5432.

$ cat dockerfile/postgres/goss/goss.yaml

port:
  tcp:5432:
    listening: true

Archivos goss de nginx

La primera comprobación que hará nginx será verificar si tiene abierto el puerto 443.

$ cat dockerfile/nginx/goss/goss.yaml

port:
  tcp:443:
    listening: true

Utilizaremos nginx como servicio principal para comprobar todos los demás servicios, será el último en levantarse completamente ya que tiene que esperar a que los otros servicios hayan realizado sus comprobaciones.

Agregaremos las comprobaciones a los servicios y si algún servicio no funciona dicha comprobación podemos verificar su funcionamiento de otra forma, por ejemplo, el servicio de portainer hemos realizado una llamada a la web y si devuelve un código 200 significa que ha podido levantarse correctamente.

$ cat dockerfile/nginx/goss/goss-command.yaml 

addr:
  tcp://postgres-odoo:5432:
    reachable: true
    timeout: 500
  tcp://odoo14:8069:
    reachable: true
    timeout: 500

http:
  http://portainer-odoo:9000:
    status: 200
    allow-insecure: false
    no-follow-redirects: false
    timeout: 5000
    body: []

Agregamos goss al dockerfile

Para utilizar Goss desde un Dockerfile, primero se debe añadir la instrucción para instalar  en el sistema. Esto se puede hacer utilizando el comando de instalación proporcionado por el proyecto o utilizando una imagen de contenedor previamente construida con Goss ya instalado.

Una vez instalado Goss, se pueden añadir las instrucciones para copiar los archivos de prueba de Goss al contenedor y ejecutar Goss. Por ejemplo, se puede agregar una instrucción COPY para copiar los archivos de prueba desde el sistema de archivos del host al contenedor, y luego una instrucción CMD o ENTRYPOINT para ejecutar y realizar las pruebas.

Vamos a configurar los Dockerfiles de nuestra infraestructura.

Dockerfile de Odoo

FROM odoo:14.0

USER root

RUN apt-get update
RUN apt-get install curl -y

ENV GOSS_VERSION v0.3.11
RUN curl -L https://github.com/aelsabbahy/goss/releases/download/$GOSS_VERSION/goss-linux-amd64 -o /usr/local/bin/goss && \
    chmod +rx /usr/local/bin/goss && \
    goss --version

COPY goss/ /goss

USER odoo

CMD goss -g /goss/goss-command.yaml validate -r 5m && exec odoo

HEALTHCHECK --interval=1s --timeout=6s CMD goss -g /goss/goss.yaml validate

Este ejemplo utiliza una imagen base de Odoo 14, instala Goss, copia el directorio, este tendrá los dos archivos creados previamente, al contenedor y ejecutalo para validar el servicio web.

Realizamos dos comprobaciones primero ejecutamos el archivo goss-command.yaml y tras su verificación inicia Odoo. Luego, realiza un Healthcheck cada segundo con la verificación del archivo goss.yaml.

Dockerfile de postgres

FROM postgres:12.8

USER root

RUN apt update

RUN apt install curl -y

ENV GOSS_VERSION v0.3.11
RUN curl -L https://github.com/aelsabbahy/goss/releases/download/$GOSS_VERSION/goss-linux-amd64 -o /usr/local/bin/goss && \
    chmod +rx /usr/local/bin/goss && \
    goss --version

COPY goss/ /goss

HEALTHCHECK --interval=1s --timeout=6s CMD goss -g /goss/goss.yaml validate

Ejemplo similar, pero con la imagen base de postgres pero con sus respectivas comprobaciones.

Es importante mencionar que al ejecutar las pruebas desde dentro de un contenedor, las pruebas estarán validando la configuración y el comportamiento del servicio dentro del contexto del contenedor, en lugar de en el host.

Estado de los servicios

Un contenedor Docker puede tener tres estados de salud diferentes: “healthy”, “unhealthy” o “health: starting”.

  • “Healthy” significa que el contenedor se está ejecutando correctamente y cumpliendo con todas las condiciones de salud especificadas.
  • “Unhealthy” significa que el contenedor no está cumpliendo con alguna de las condiciones de salud especificadas. Esto puede deberse a un problema con el servicio que se está ejecutando dentro del contenedor o a un problema con el propio contenedor.
  • “Health: starting” significa que el contenedor está iniciando y aún no se ha determinado su estado de salud. Puede ser porque el servicio todavía no ha terminado de iniciar o porque aún no se han ejecutado las pruebas de salud.

Levantamos los servicios

Una vez agregadas las instrucciones, se puede utilizar el comando “docker-compose up -d” para iniciar los contenedores y ejecutar las pruebas de Goss automáticamente.

Puedes usar el comando “docker-compose ps” para ver el estado de los contenedores en tu compose file. Si un contenedor está “healthy”, se mostrará junto a “Up”. Si un contenedor está fallando se mostrará como “unhealthy”.

$ docker-compose ps
     Name                   Command                  State                                       Ports                                 
---------------------------------------------------------------------------------------------------------------------------------------
metabase         /app/run_metabase.sh /bin/ ...   Up (healthy)   3000/tcp                                                              
netdata          time bash starter.sh             Up (healthy)   0.0.0.0:19999->19999/tcp,:::19999->19999/tcp                          
nginx-odoo       /docker-entrypoint.sh /bin ...   Up (healthy)   0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0:80->80/tcp,:::80->80/tcp
odoo14           /entrypoint.sh /bin/bash - ...   Up (healthy)   0.0.0.0:8069->8069/tcp,:::8069->8069/tcp, 8071/tcp, 8072/tcp          
portainer-odoo   /portainer --admin-passwor ...   Up             9000/tcp                                                              
postgres-odoo    docker-entrypoint.sh postgres    Up (healthy)   0.0.0.0:5432->5432/tcp,:::5432->5432/tcp   

¿Qué pasa si se cae un servicio?

Vamos a parar el servicio de la base de datos simulando que se ha caído la base de datos o directamente no se ha podido levantar por algún motivo.

Para detener un servicio específico en un archivo de compose, puedes usar el comando “docker-compose stop [nombre del servicio]“.

$ docker-compose stop postgres-odoo
Stopping postgres-odoo ... done

Una vez que hayas detenido el servicio, puedes verificar de nuevo el estado con docker-compose ps, donde podemos ver que los servicios que tenemos comprobando postgres están unhealthy o intentando iniciar.

devops@chakray:~/gitlab-chakray/chdo/chdo-odoo-platform/odoo14-compose$ docker-compose ps
     Name                   Command                       State                                           Ports                                 
------------------------------------------------------------------------------------------------------------------------------------------------
metabase         /app/run_metabase.sh /bin/ ...   Up (healthy)            3000/tcp                                                              
netdata          time bash starter.sh             Up (health: starting)   0.0.0.0:19999->19999/tcp,:::19999->19999/tcp                          
nginx-odoo       /docker-entrypoint.sh /bin ...   Up (unhealthy)          0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0:80->80/tcp,:::80->80/tcp
odoo14           /entrypoint.sh /bin/bash - ...   Up (health: starting)   0.0.0.0:8069->8069/tcp,:::8069->8069/tcp, 8071/tcp, 8072/tcp          
portainer-odoo   /portainer --admin-passwor ...   Up                      9000/tcp                                                              
postgres-odoo    docker-entrypoint.sh postgres    Exit 0 

Si quieres verificar el estado de salud de los contenedores en tiempo real, puedes usar el comando “docker-compose logs -f” para ver los registros de los contenedores mientras están ejecutándose.

nginx-odoo        | Attempt #177:
nginx-odoo        | ...F
nginx-odoo        | 
nginx-odoo        | Failures/Skipped:
nginx-odoo        | 
nginx-odoo        | Addr: tcp://postgres-odoo:5432: reachable:
nginx-odoo        | Expected
nginx-odoo        |     <bool>: false
nginx-odoo        | to equal
nginx-odoo        |     <bool>: true
nginx-odoo        | 
nginx-odoo        | Total Duration: 0.010s
nginx-odoo        | Count: 4, Failed: 1, Skipped: 0
nginx-odoo        | Retrying in 1s (elapsed/timeout time: 177.516s/5m0s)

“Count” es el número total de pruebas que se ejecutan. “Failed” es el número de pruebas que fallaron y “Skipped” es el número de pruebas que se saltaron en la ejecución.

Por ejemplo, si el resultado de ejecutar es “Count: 4, Failed: 1, Skipped: 0”, significa que se ejecutaron 4 pruebas en total, una de ellas falló y no se saltó ninguna.

En caso de que haya alguna prueba fallida, te mostrará detalles sobre qué pruebas fallaron y por qué. Puedes usar esta información para corregir los problemas y volver a ejecutar las pruebas fallidas.

El servicio vuelve a funcionar

Una vez que hayas solucionado los problemas que causaron que el servicio cayera y lo iniciamos nuevamente y volvemos a verificar si el contenedor está en un estado saludable.

devops@chakray:~/gitlab-chakray/chdo/chdo-odoo-platform/odoo14-compose$ docker-compose up -d
netdata is up-to-date
portainer-odoo is up-to-date
Starting postgres-odoo ... done
metabase is up-to-date
odoo14 is up-to-date
nginx-odoo is up-to-date

Vemos que ya ha conectado y nos hemos asegurado de que el resultado sea Count: [x], Failed: 0, Skipped: 0”, lo que indica que todas las pruebas han pasado exitosamente y no hay errores.

nginx-odoo        | Attempt #272:
nginx-odoo        | ...F
nginx-odoo        | 
nginx-odoo        | Failures/Skipped:
nginx-odoo        | 
nginx-odoo        | Addr: tcp://postgres-odoo:5432: reachable:
nginx-odoo        | Expected

nginx-odoo        |     <bool>: false

nginx-odoo        | to equal

nginx-odoo        |     <bool>: true

nginx-odoo        |

nginx-odoo        | Total Duration: 0.005s

nginx-odoo        | Count: 4, Failed: 1, Skipped: 0

nginx-odoo        | Retrying in 1s (elapsed/timeout time: 273.438s/5m0s)

nginx-odoo        |

nginx-odoo        |

nginx-odoo        | Attempt #273:

nginx-odoo        | ....

nginx-odoo        |

nginx-odoo        | Total Duration: 0.004s

nginx-odoo        | Count: 4, Failed: 0, Skipped: 0

Si todavía tienes problemas con el contenedor, puedes revisar de nuevo los registros del contenedor con el comando “docker-compose logs [nombre del servicio]” para obtener más información sobre el problema.

Mapear goss

¿Por qué mapear un archivo?

Mapear un archivo goss.yaml en un contenedor de Docker tiene varias ventajas:

  1. Mejora la flexibilidad: Al mapear un archivo goss.yaml en un contenedor, puedes personalizar la configuración  para adaptarse a tus necesidades específicas, en lugar de estar limitado por la configuración predeterminada del Dockerfile.
  2. Permite la reutilización de la configuración: Al mapear un archivo goss.yaml en un contenedor, puedes reutilizar la misma configuración  en varios contenedores o entornos diferentes, en lugar de tener que crear una configuración diferente para cada contenedor o entorno.
  3. Facilita la actualización de la configuración: Al tener la configuración fuera del contenedor, puedes actualizarla fácilmente sin tener que reconstruir la imagen del contenedor.

En resumen, mapear un archivo goss.yaml en un contenedor de Docker te permite tener un mayor control sobre la configuración , mejorar la flexibilidad y facilitar el desarrollo y la actualización.

Mapeando un archivo de configuración Goss

Puedes mapear un archivo de configuración en un contenedor de Docker al momento de construir la imagen o al momento de ejecutar el contenedor.

Para ello creamos el archivo con el mismo nombre en un directorio. En este archivo agregamos las comprobaciones que necesitemos.

$ cat configs/odoo14/goss-command.yaml 

addr:
  tcp://postgres-odoo:5432:
    reachable: true
    timeout: 500

command:
  PGPASSWORD=${MY_PASSWORD} psql -h postgres-odoo -U ${MY_USER} -d postgres:
    title: Ensure we have valid credentials
    exit-status: 0
    timeout: 50000 # 5s

Al mapear un archivo goss.yaml en un contenedor de Docker, se sobrescribirá cualquier configuración especificada en el archivo Dockerfile original de la imagen. Esto se debe a que el archivo goss.yaml mapeado se vincula con el contenedor en tiempo de ejecución, y tiene prioridad sobre cualquier configuración especificada en el archivo Dockerfile.

Es importante tener en cuenta que esto solo se aplica a la configuración. Si hay algún cambio en el contenedor que no se refiera a Goss, como una dependencia de software, cambios en el sistema de archivos, etc, estos no serán afectados por el archivo goss mapeado.

Configuración del docker-compose.yml

Para mapear un archivo goss.yaml en un contenedor de Docker cuando se utiliza Docker Compose, debes especificar la ruta del archivo goss.yaml en tu sistema de archivos local en el archivo compose y la ruta dentro del contenedor donde se desea colocar el archivo goss.yaml.

Por ejemplo, si tu archivo goss.yaml se encuentra en la ruta “./configs/odoo14/goss-command.yaml” y deseas mapearlo en el contenedor en la ruta “/goss/goss-command.yaml”, en tu archivo compose podrías agregar la siguiente línea en el servicio correspondiente:

volumes:
      - ./configs/odoo14/goss-command.yaml:/goss/goss-command.yaml

Una vez hecho esto, al ejecutar el comando “docker-compose up -d” se creará un enlace entre el archivo goss.yaml en tu sistema de archivos local y el contenedor, permitiendo a Goss acceder a la configuración especificada en ese archivo.

Conclusión

En resumen, Goss es una herramienta de validación de sistemas que se puede utilizar para verificar si los contenedores de Docker están en un estado saludable. Es una herramienta muy útil para automatizar las pruebas y asegurar que los contenedores cumplen con tus requisitos de configuración.

Puedes utilizar Goss junto con Docker Compose para verificar el estado de salud de tus contenedores, y mapear un archivo goss.yaml en un contenedor de Docker para tener un mayor control sobre la configuración, mejorar la flexibilidad y facilitar el desarrollo y la actualización.

Si necesitas más información sobre cómo utilizar esta herramienta, podemos proporcionarte recursos y asistencia para ayudarte a implementarlo en su proyecto de manera efectiva. Estamos dispuestos a brindarte toda la ayuda necesaria para asegurar que su uso sea un éxito. Si quieres más información contacta con nosotros.