Introducción a la monitorización con Grafana y Loki

per Victor Carceler darrera modificació 2023-12-09T22:02:45+02:00

logo.pngGrafana Loki es un agregador de logs eficiente, escalable y con el que es muy sencillo trabajar.

Se inspira en Prometheus pero en lugar de guardar métricas guarda mensajes de log (o de systemd-journald). Y a diferencia de otras soluciones (como OpenSearch) no indexa el contenido de cada mensaje sino únicamente sus metadatos con unas etiquetas idénticas a las que se utilizan en Prometheus.

Así no se requiere mucha CPU al ingerir los datos y dado que los datos se guardan comprimidos ocupan mucho menos espacio que al utilizar systemd-journald(que no es que sea especialmente eficiente al utilizar el espacio de disco).

Cuando se desea consultar información Loki puede procesar con gran velocidad los datos seleccionados para presentar los resultados.

La pila estará compuesta por:

  • loki que almacena de manera centralizada los logs de diferentes máquinas y permite la consulta de esos datos con LogQL.
  • promtail instalado en cada uno de los ordenadores que enviarán datos a loki. Puede enviar los ficheros de registro o journal.
  • grafana para explorar y visualizar los datos.

Instalación básica de loki

Los desarrolladores proporcionan binarios y paquetes para las principales distribuciones. En el momento de escribir esta introducción la última versión publicada es 2.9.2 así que podremos descargar el paquete loki_2.9.2_amd64.deb .

Por ejemplo, utilizando un contenedor LXD podremos instalar la aplicación:

root@loki:~# wget https://github.com/grafana/loki/releases/download/v2.9.2/loki_2.9.2_amd64.deb
root@loki:~# apt install ./loki_2.9.2_amd64.deb

Y modificar el fichero de configuración /etc/loki/config.yml para que:

  • Se utilice el directorio /var/loki para guardar los datos.
  • Se utilice TSDB para guardar la información en lugar del formato anterior (boltdb-shipper).
  • El periodo de retención de datos sea de 30 días.
  • Se utilicen hasta 4 CPUs y se incrementan algunos límites.

Así la configuración que utilizamos en el centro es:

auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096
  # No queremos tantos mensajes
  log_level: warn

common:
  instance_addr: 127.0.0.1
  path_prefix: /var/loki
  storage:
    filesystem:
      chunks_directory: /var/loki/chunks
      rules_directory: /var/loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory

compactor:
  working_directory: /var/loki/retention
  shared_store: filesystem
  compaction_interval: 10m
  retention_enabled: true
  retention_delete_delay: 2h
  retention_delete_worker_count: 150

schema_config:
  configs:
    - from: "2023-11-20"
      index:
        period: 24h
        prefix: index_
      object_store: filesystem
      schema: v12
      store: tsdb

query_scheduler:
  # the TSDB index dispatches many more, but each individually smaller, requests. 
  # We increase the pending request queue sizes to compensate.
  max_outstanding_requests_per_tenant: 32768

querier:
  # Each `querier` component process runs a number of parallel workers to process queries simultaneously.
  # You may want to adjust this up or down depending on your resource usage
  # (more available cpu and memory can tolerate higher values and vice versa),
  # but we find the most success running at around `16` with tsdb
  max_concurrent: 16

ruler:
  alertmanager_url: http://localhost:9093

# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration
# analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/
#
# Statistics help us better understand how Loki is used, and they show us performance
# levels for most users. This helps us prioritize features and documentation.
# For more information on what's sent, look at
# https://github.com/grafana/loki/blob/main/pkg/usagestats/stats.go
# Refer to the buildReport method to see what goes into a report.
#
# If you would like to disable reporting, uncomment the following lines:
#analytics:
#  reporting_enabled: false

# Ver: https://github.com/grafana/loki/issues/5123
#
frontend:
  max_outstanding_per_tenant: 4096

# Ver: https://community.grafana.com/t/maximum-of-series-500-reached-for-a-single-query/64117/4
#
limits_config:
  max_query_series: 10000
  max_query_parallelism: 4
  retention_period: 30d

Loki guarda los datos comprimidos con muchísima más eficiencia que systemd-journald. Así que puede resultar recomendable reducir en /etc/systemd/journald.conf el valor por defecto de SystemMaxUse (que en Ubuntu son 4GB) en todas aquellas máquinas que estén utilizando promtail para enviar los datos a Loki.

El despliegue del centro está guardando los journald de unos pocos servidores. El servidor que más volumen de información registra es un gateway que tiene activo el registro de consultas de bind9 y en una hora punta puede generar aproximadamente 1GiB de datos de journald por hora.

Sin embargo los datos de todo un mes para ese servidor y otros pocos que registran un menor volumen de información en Loki consumen aproximadamente 1.6GB.Y estos datos se pueden guardar en disco (como estamos haciendo nosotros) o enviar a un object storage como MinIO (o algún servicio cloud) para conseguir mayores capacidades.

Instalación de promtail

La instalación de promtail se puede hacer a partir de los paquetes proporcionados en cada lanzamiento. Bastará con descargar e instalar la última versión disponible.

wget https://github.com/grafana/loki/releases/download/v2.9.2/promtail_2.9.2_amd64.deb
apt install ./promtail_2.9.2_amd64.deb

Pero después será necesario editar /etc/group y añadir el usuario promtail al grupo adm para que gane acceso a los ficheros de registro y a journal.

vcarceler@cirdan-2204:~$ cat /etc/group | grep adm
adm:x:4:syslog,vcarceler,promtail
vcarceler@cirdan-2204:~$

Para enviar los ficheros de registro /var/log/*log a Loki (que está en 192.168.0.24) se puede utilizar la siguiente configuración:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://192.168.0.24:3100/loki/api/v1/push

scrape_configs:
- job_name: system
  static_configs:
  - targets:
      - localhost
    labels:
      job: varlogs
      __path__: /var/log/*log

Y para enviar los datos de systemd-journald la configuración que utilizamos es:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://192.168.0.24:3100/loki/api/v1/push

scrape_configs:
- job_name: journal
  journal:
    max_age: 12h
    path: /var/log/journal
    labels:
      job: systemd-journal
  relabel_configs:
    - source_labels: ['__journal__systemd_unit']
      target_label: 'unit'
    - source_labels:
      - __journal__hostname
      target_label: nodename

Al configurar promtail para enviar journal a Loki de esta manera se añaden automáticamente las etiquetas nodename y unit para clasificar los datos por máquina y servicio.

Consultas desde Grafana

Finalmente podremos acceder a Grafana (la instalación es muy sencilla) para representar nuestros datos.

Después podremos explorar los registros seleccionando las etiquetas que queramos. Por ejemplo: nodename y unit.

Captura desde 2023-12-09 20-04-30.png

Debajo de la representación temporal de las entradas de log podremos encontrar los datos:

Captura desde 2023-12-09 20-13-47.png

A partir de aquí se podrán utilizar todas las funciones de LogQL para consultar la información que nos interese. Filtrando líneas que contengan (o no contengan) lo que nos interese, extrayendo campos (con los parsers JSON,logfmtpattern o regular expression) y aplicando metric queries para generar métricas a partir de las líneas de log.

Por ejemplo, sabiendo que BIND9 registra las consultas de los clientes con el siguiente formato:

client @0x7f7c7cc06c68 192.168.21.63#44327 (pool.ntp.org): query: pool.ntp.org IN A + (192.168.21.10)

La siguiente consulta:

topk(25, sum by(client) (count_over_time({nodename="$nodename", unit="named.service"} 
|= `client @`
!= `denied`
!= `query failed`
| pattern `client @<_> <client>#<clientport> (<query>): query: <_> IN <type> +<extra> (<server>)` | __error__="" [$__range])))
  • Selecciona el stream que tiene las etiquetas nodename y unit con los valores que nos interesan.
  • Acepta líneas que contengan 'client @'.
  • Descarta líneas que contengan 'denied' o 'query failed'.
  • Utiliza el parser pattern para extraer el valor de los campos: client, clientport, query, type, extra y server.
  • Cuenta las líneas haciendo una suma para cada valor de client (la IP del ordenador que consulta al DNS).
  • Retornando los 25 ordenadores que han hecho más consultas.

Lo que permite representar el siguiente panel con una visualización pie chart:

Captura desde 2023-12-09 20-44-53.png

Y así podremos componer el dashboard que muestre la información que nos sea útil, como el que hemos hecho para mostrar información sobre las consultas que recibe nuestro DNS (dashboard disponible en: https://grafana.com/grafana/dashboards/20079-loki-bind9/).

Captura desde 2023-12-09 20-50-51.png

Más información: