Loki - aleiis/grafana-stack-validation GitHub Wiki
Loki es un sistema de almacenamiento y consulta de logs altamente eficiente y distribuido. Loki está diseñado para trabajar con logs en grandes volúmenes sin requerir un índice pesado, lo que lo hace más eficiente y escalable. Este sistema permite almacenar, indexar y consultar logs de aplicaciones, servicios y sistemas de manera centralizada. Loki puede integrar logs con métricas a través de labels compartidas, lo que facilita correlacionar logs con las métricas de Prometheus.
En esta sección se explica el proceso de configuración y la recolección e ingesta de logs en Loki. La documentación tecnica de Loki puede encontrarse en su sitio oficial: https://grafana.com/docs/loki/latest/
Captura y rotación de logs
La captura de logs depende del entorno en el que estén corriendo nuestras aplicaciones. En este caso nuestros servicios están corriendo sobre Docker. La mejor forma de manejar los logs para aplicaciones que se van a ejecutar en un contenedor de Docker es enviar los logs a stdout
(en vez de a un fichero) para que sea Docker quien los gestione. Este patrón podemos observarlo en la mayoría de aplicaciones para contenedores.
Docker gestionará los logs de una forma u otra dependiendo del logging driver que tengamos configurado. Es importante que el logging driver configurado soporte log rotation para evitar que los ficheros de logs que mantiene Docker crezcan demasiado y ocupen todo el espacio en disco. Por defecto, Docker usa json-file
como logging driver, que cachea internamente los logs de los contenedores en formato JSON. Sin embargo, json-file
no tiene habilitada la rotación de logs por defecto, además de que el formato JSON puede suponer una sobrecarga innecesaria. Docker mantiene json-file
(sin rotación de logs) como predeterminado para mantener la compatibilidad con versiones anteriores de Docker y para situaciones en las que Docker se utiliza como runtime para Kubernetes.
Una opción es mantener json-file
como driver y ponerle un valor adecuado a estas dos opciones que tiene el driver json-file
:
-
max-size
: El tamaño máximo del log antes de que se rote. Es un entero positivo seguido de un modificador que representa la unidad de medida ('k', 'm' o 'g'). Por defecto es -1 (ilimitado). -
max-file
: El número máximo de archivos de log que pueden estar presentes. Si al rotar los logs se crean archivos en exceso, el archivo más antiguo se elimina. Solo es efectivo cuando también se establecemax-size
. Es un entero positivo. Por defecto es 1.
Otra opción es cambiar el driver a local
, que utiliza un formato propio para minimizar el overhead y rota los logs de forma predeterminada. Este driver es el que se recomienda en la documentación de Docker. También admite la opción max-file
.
Para configurar Docker para que use un driver específico por defecto, cambia el valor de log-driver
al driver que quieras utilizar en el archivo de configuración daemon.json
.
Si quieres modificar el driver para un contenedor en concreto dentro de tu fichero docker-compose.yaml
añade la sección logging
. Por ejemplo:
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "3"
Más información sobre los drivers de logging de Docker: https://docs.docker.com/engine/logging/configure/
Recolección e ingesta de logs
Grafana Alloy nos permite recolectar todos los logs que almacena Docker, procesarlos y enviarlos a Loki. Grafana Alloy tiene una arquitectura basada en componentes que puedes acoplar como mejor necesites para gestionar el flujo de datos de observabilidad entre distintos servicios. Tanto los componentes que queremos utilizar como su comportamiento se define en un YAML de configuración.
Loki recibe los logs enviados por Grafana Alloy para después ser procesados, almacenados e indexados de forma eficiente en una base de datos distribuida diseñada para gestionar grandes volúmenes de logs de manera eficiente. Si queremos consultar métricas almacenadas en Loki podemos hacerlo utilizando LogQL.
Configuración
Grafana Alloy
Grafana Alloy se encarga de la recopilación, transformación y entrega de datos de telemetría. Solo necesita un archivo de configuración que describa su comportamiento. Configura y conecta dinámicamente los componentes utilizando su propia sintaxis de configuración. Cada componente en la configuración realiza una de estas tareas o especifica cómo fluyen los datos y cómo se vinculan los componentes entre sí.
La sintaxis de Alloy utiliza bloques, atributos y expresiones. Se basa en una estructura declarativa que organiza configuraciones mediante bloques, los cuales definen componentes o tareas específicas. Dentro de estos bloques, se utilizan atributos para establecer propiedades o comportamientos, y expresiones para definir valores, conexiones o transformaciones.
prometheus.remote_write "default" {
endpoint {
url = "http://localhost:9009/api/prom/push"
}
}
El ejemplo anterior contiene dos bloques:
-
Un bloque etiquetado,
prometheus.remote_write "default"
, que instancia un componenteprometheus.remote_write
. La etiqueta es la cadena"default"
. -
Un bloque sin etiqueta dentro del componente,
endpoint
, que configura un endpoint para enviar métricas. Este bloque define el atributourl
para especificar el endpoint.
En nuestro caso, para realizar realizar todo el proceso de recolección e ingesta de logs para Loki desde Docker hemos utilizado cuatro componentes (ver config.alloy
):
-
El bloque
discovery.docker "docker_discovery"
configura un componente de descubrimiento de Docker etiquetado como"docker_discovery"
con los siguientes argumentos:host
: Especifica la ubicación del socket de Docker para interactuar con el daemon. Es importante compartir con el contenedor de Alloy el socket de Docker utilizando volúmenes para que Alloy pueda tener acceso.refresh_interval
: Indica cada cuanto tiempo se actualiza el descubrimiento de contenedores.
-
El bloque
discovery.relabel "docker_relabel"
define reglas de relabeling para transformar o añadir etiquetas a los datos descubiertos:- El bloque
rule
define una regla interna con los siguientes argumentos:source_labels
: Etiqueta de origen (__meta_docker_container_name
).regex
: Aplica una expresión regular para extraer el nombre del contenedor.target_label
: Crea una nueva etiqueta llamadacontainer
con el valor procesado.
- El bloque
-
El bloque
loki.source.docker "docker_scraping"
configura la recopilación de logs desde los contenedores Docker:host
: Define la ubicación del socket de Docker.targets
: Usa los contenedores detectados pordocker_discovery
.forward_to
: Los datos recopilados se envían al componenteloki_push
.relabel_rules
: Aplica las reglas definidas endocker_relabel
.refresh_interval
: Tiempo de actualización.
-
El bloque
loki.write "loki_push"
define la conexión con Loki para almacenar los logs:endpoint
: Especifica la URL del servidor Loki donde se enviarán los datos (http://loki:3100/loki/api/v1/push
).external_labels
: Permite añadir etiquetas adicionales a los datos enviados.
Más información sobre Grafana Alloy en su documentación: https://grafana.com/docs/alloy/latest/
Loki
La arquitectura, el funcionamiento y las características que convierten a Loki en una buena solución para almacenar y consultar logs de forma distribuida son muy similares a las de Cortex. Loki sigue una arquitectura basada en microservicios muy similar a la de Cortex, solo que con algunas sutiles diferencias dada la naturaleza de los logs.
En este caso, Loki se despliega de forma monilítica, es decir, todos los componentes de Loki corren en el mismo proceso. El modo monolítico se activa añadiendo la sentencia target: all
al YAML de configuración (de hecho, all
es el valor por defecto de target
) o añadiendo el parámetro -target=all
a la línea de comandos.
Más información sobre los modos de despliegue de Loki: https://grafana.com/docs/loki/latest/get-started/deployment-modes/
Además de esto, hay que configurar debidamente Loki a traves de un YAML de configuración, aunque muchos valores pueden mantenerse por defecto y no es necesario declararos. A pesar de que existen varios casos de uso, los cuales pueden verse en su documentación, nosotros hemos definido los siguientes campos:
-
auth_enabled
: Desactiva la autenticación, lo que significa que no es necesario proporcionar una cabeceraX-Scope-OrgID
en las solicitudes HTTP, y se utiliza un valor ficticio (fake
) por defecto. -
server
: Define la configuración del servidor, como el puerto HTTP en el que escuchará (3100
). -
common
: Contiene configuraciones generales del sistema.ring.instance_addr
: Dirección IP local utilizada por Loki.ring.kvstore.store
: Configura el almacenamiento del estado del anillo en memoria (inmemory
).replication_factor
: Establece el factor de replicación de los datos para en caso de fallo de alguno de los componentes.path_prefix
: Define el directorio base donde Loki almacenará sus archivos.
-
schema_config
: Configura el esquema del indice de chunks y donde se guarda.-
configs
: Lista de configuraciones para el esquema del índice de chunks para un periodo de tiempo determinado.from
: Fecha a partir de la cual será utilizada este esquema.store
: Índice utilizado en este esquema.object_store
: Almacenamiento de objetos utilizado en este esquema.schema
: Versión utilizada en este esquema. Recomendadov13
.index
: Define como se actualiza y se guarda el índice. Por ejemplo, define el prefijo para todas las tablas de periodos y el periodo de las tablas.
-
-
storage_config
: Configura dónde y cómo Loki almacenará los logs. Utiliza almacenamiento en el sistema de archivos local (filesystem
), aunque también se pueden usar otros servicios como S3, GCS o Azure. El sistema de archivos local solo debe utilizarse como demostrador, para producción debería configurarse otro servicio.
Para ver todos los valores que se pueden configurar o necesita ayuda para redactar su propio archivo de configuración puede referirse a la referencia de configuración de Loki: https://grafana.com/docs/loki/latest/configure/.