Loki de A à Y
Loki est un système de gestion de logs open source et conçu par Grafana Labs. Il est connu pour être facile d’utilisation et très performant. Loki est conçu pour être utilisé avec Grafana via l’usage d’un équivalent au LogQL, un langage de requête similaire à celui de Prometheus (pour en savoir plus sur Prometheus, cliquez ici).
Dans cet article, nous allons voir comment installer l’ensemble des composants nécessaires pour utiliser Loki et Promtail. Nous verrons aussi comment stocker les logs sur un stockage objet (Minio) pour avoir une haute disponibilité dans un cluster de Loki.
Architecture de Loki
L’architecture de Loki est composée de trois éléments principaux :
- Loki : le serveur de stockage de logs, il fait office de base de données pour les logs.
- Promtail : l’agent de collecte de logs, il est responsable de la collecte des logs et de leur envoi à Loki.
- Grafana : l’interface utilisateur pour visualiser les logs stockés dans Loki.
Astuce
Promtail peut être remplacé par d’autres agents de collecte de logs, comme Fluentd, Fluent Bit, ou Logstash (nous n’aborderons que la partie Promtail dans cet article).
Un des avantages de Loki est qu’il permet de stocker les logs sur un stockage objet (comme S3, GCS, ou Azure Blob Storage) ou sur un système de fichiers local.
Nous allons commencer par utiliser le stockage local, puis nous utiliserons Minio pour stocker les logs sur un stockage objet afin d’avoir une haute disponibilité.
Pourquoi sur Minio ?
Parce que l’usage du stockage local ne permet pas d’avoir une haute disponibilité. En effet, Loki ne supporte pas le clustering avec un stockage local (à moins de bricoler quelque chose avec un stockage NFS mais .. berk ). ⬇️
Running Loki clustered is not possible with the filesystem store unless the filesystem is shared in some fashion (NFS for example). However using shared filesystems is likely going to be a bad experience with Loki just as it is for almost every other application.
Installation de Loki et Promtail
Pour cette primo-installation, je vais passer par le dépôt officiel de Grafana:
mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor > /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | tee /etc/apt/sources.list.d/grafana.list
Une fois les dépôts ajoutés, nous pouvons installer Loki et Promtail à coup de apt
:
apt update
apt install -y promtail loki
Pour vérifier que Loki soit bien fonctionnel, je peux afficher le /metrics
de Loki:
$ curl 192.168.1.73:3100/metrics -s | tail -n 5
ring_member_tokens_owned{name="scheduler"} 1
# HELP ring_member_tokens_to_own The number of tokens to own in the ring.
# TYPE ring_member_tokens_to_own gauge
ring_member_tokens_to_own{name="compactor"} 1
ring_member_tokens_to_own{name="scheduler"} 1
Remarque
Qu’est-ce que le /metrics ?
C’est le chemin utilisé par Prometheus pour récupérer les métriques exposées par Loki. Pour approfondir l’usage de ces données, vous pouvez faire un tour sur mon article sur Prometheus.
Par défaut, Promtail va envoyer les logs dans le fichier /var/log/messages
à Loki via l’URL http://localhost:3100/loki/api/v1/push
. On peut alors installer logcli
, un utilitaire en ligne de commande pour interagir avec Loki:
apt install logcli -y
Une fois installé, nous pouvons afficher les logs envoyés par Promtail:
$ logcli labels job
2024/02/07 07:09:56 http://localhost:3100/loki/api/v1/label/job/values?end=1707286196102901828&start=1707282596102901828
Si, comme moi, vous n’avez qu’une URL qui s’affiche en réponse, c’est que Promtail n’a pas encore envoyé de log à Loki (réponse vide). C’est parce que dans ma configuration, Promtail ne surveille que le fichier /var/log/messages
… qui n’existe pas sur mon système. Je vais alors remplacer ce fichier par /var/log/dpkg.log pour avoir des logs à afficher et …
$ logcli labels job
2024/02/07 07:19:26 http://localhost:3100/loki/api/v1/label/job/values?end=1707286766300993936&start=1707283166300993936
varlogs
Victoire ! Promtail a bien envoyé des logs à Loki. Je peux aussi les afficher avec ma première requête de LogQL '{job="varlogs"}'
:
$ logcli query '{job="varlogs"}'
2024/02/07 07:21:59 http://localhost:3100/loki/api/v1/query_range?direction=BACKWARD&end=1707286919240803766&limit=30&query=%7Bjob%3D%22varlogs%22%7D&start=1707283319240803766
2024/02/07 07:21:59 Common labels: {filename="/var/log/dpkg.log", job="varlogs"}
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 status installed logcli:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 status half-configured logcli:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 status unpacked logcli:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 configure logcli:amd64 2.9.4 <none>
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 startup packages configure
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 status unpacked logcli:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 status half-installed logcli:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 install logcli:amd64 <none> 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 19:09:38 startup archives unpack
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:11 status installed promtail:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:09 status half-configured promtail:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:09 status unpacked promtail:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:09 configure promtail:amd64 2.9.4 <none>
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:09 status installed loki:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:08 status half-configured loki:amd64 2.9.4
2024-02-07T07:18:43+01:00 {} 2024-02-06 18:30:08 status unpacked loki:amd64 2.9.4
Installer Grafana
Grafana est un outil de visualisation de données open source. Il est souvent utilisé pour visualiser les métriques de Prometheus, mais il peut aussi être utilisé pour visualiser les logs stockés dans Loki.
J’installe Grafana sur un autre serveur que celui hébergeant Loki. Le dépôt de Grafana est le même que celui de Loki.
mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor > /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | tee /etc/apt/sources.list.d/grafana.list
apt update
apt install -y grafana
systemctl enable --now grafana-server
Grafana est disponible sur le port :3000
par défaut. Pour y accéder, il suffit de se rendre sur l’URL http://<ip>:3000
et de se connecter avec les identifiants par défaut (admin/admin).
On va ensuite ajouter la source de données Loki dans le menu Configuration > Data Sources > Add data source.
En dehors de l’URI de Loki (qu’est http://loki-01:3100
dans mon cas), je vais laisser les autres champs par défaut.
Via l’interface web de Grafana, on peut aller dans l’onglet Explore
pour visualiser les logs stockés dans Loki.
Le formulaire de requête est le Query Builder, il permet de construire (et d’exécuter) des requêtes pour Loki. Je peux, par exemple, sélectionner le job varlogs
pour afficher le contenu du fichier /var/log/dpkg.log
sur la machine loki.
Le LogQL
Introduction à LogQL
LogQL est un langage de requête conçu spécifiquement pour interroger et filtrer des journaux dans Loki. Il permet aux utilisateurs d’extraire des données pertinentes à partir de grands ensembles de journaux de manière efficace.
Principes de base de LogQL
Sélection des journaux :
- Utilisez la clause
{}
pour sélectionner les journaux à partir desquels vous souhaitez extraire des données. Par exemple,{job="nginx"}
sélectionne tous les journaux provenant du travail (job) “nginx”. Si plusieurs jobs portent le même nomnginx
, vous pouvez rajouter de la précision à votre requête en proposant d’autres labels ({job="nginx", node="nginx-server-01"}
)
- Utilisez la clause
Filtrer les journaux :
- Utilisez les opérateurs logiques tels que
==
,!=
,=~
,!~
pour filtrer les journaux en fonction de critères spécifiques. Par exemple,{job="nginx"} |~ "error"
sélectionne les journaux du travail “nginx” qui contiennent le mot “error”.
- Utilisez les opérateurs logiques tels que
Agrégation des résultats :
- Utilisez les fonctions d’agrégation telles que
sum()
,count()
,min()
,max()
, etc., pour agréger les résultats des journaux sélectionnés. Par exemple,{job="nginx"} |~ "error" | count()
comptera le nombre total de journaux contenant le mot “error” provenant du travail “nginx”.
- Utilisez les fonctions d’agrégation telles que
Limitation des résultats :
- Utilisez la clause
| limit X
pour limiter le nombre de résultats renvoyés par votre requête. Par exemple,{job="nginx"} |~ "error" | limit 10
renverra les 10 premiers journaux contenant le mot “error” provenant du travail “nginx”.
- Utilisez la clause
Avant de continuer plus loin, je vais sécuriser les échanges entre Grafana et Loki en utilisant un certificat.
Chiffrement TLS
Pour sécuriser les échanges entre Grafana et Loki, je vais utiliser un certificat validé par une autorité de certification locale. Dans mon lab, j’utilise mkcert
, un outil qui permet de générer des certificats à l’aide d’une autorité de certification que je peux installer sur mes machines.
Installation de MKCert
MKCert est disponible dans les dépôts officiels de la plupart des distributions Linux.
apt install mkcert
apk add mkcert
yum install mkcert
nix-env -i mkcert
Générer une autorité de certification
Pour que les certificats soient considérés comme valides par Grafana/Loki, il faut que l’autorité de certification soit ajoutée au système de confiance (trust-store) de notre hôte.
$ mkcert -install
Created a new local CA 💥
The local CA is now installed in the system trust store! ⚡️
Il est possible de copier notre CA pour l’ajouter sur d’autres machines (pour que les certificats soient considérés comme valides par ces machines).
$ mkcert -CAROOT
/home/quentinj/.local/share/mkcert
La clé publique de cette autorité de certification doit être ajoutée sur la machine Grafana (pour que celle-ci accepte les certificats signés par cette autorité).
$ scp $(mkcert -CAROOT)/rootCA.pem grafana.monitoring.une-pause-cafe.fr:/usr/local/share/ca-certificates/mkcert.crt
$ ssh grafana.monitoring.une-pause-cafe.fr sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
Générer un certificat pour Loki
Sur mon poste local (ayant généré l’autorité de certification), je vais générer un certificat pour Loki:
mkcert -cert-file loki-01.monitoring.une-pause-cafe.fr.crt -key-file loki-01.monitoring.une-pause-cafe.fr.key loki-01.monitoring.une-pause-cafe.fr loki-01
J’obtiens deux fichiers, loki-01.monitoring.une-pause-cafe.fr.crt
et loki-01.monitoring.une-pause-cafe.fr.key
, qui sont respectivement le certificat et la clé privée valides pour:
loki-01.monitoring.une-pause-cafe.fr
loki-01
Sur la machine loki-01
, je vais déplacer ces fichiers dans /etc/loki/ssl
(que j’ai créé via mkdir -p /etc/loki/ssl
):
scp loki-01.monitoring.une-pause-cafe.fr.crt loki-01.monitoring.une-pause-cafe.fr.key loki-01.monitoring.une-pause-cafe.fr:/etc/loki/ssl
Je vais ensuite modifier le fichier de configuration de Loki pour lui indiquer d’utiliser ces certificats :
server:
http_listen_port: 3100
http_tls_config: # <---- Ajout de cette section
cert_file: /etc/loki/ssl/loki-01.monitoring.une-pause-cafe.fr.crt # <---- Certificat
key_file: /etc/loki/ssl/loki-01.monitoring.une-pause-cafe.fr.key # <---- Clé privée
# [...]
Après avoir redémarré Loki, je peux vérifier que le chiffrement est bien en place en utilisant curl
:
$ curl -I https://loki-01.monitoring.une-pause-cafe.fr:3100/metrics
HTTP/2 200
content-type: text/plain; version=0.0.4; charset=utf-8
[...]
Pas d’erreur, le chiffrement est bien en place !
⚠️ Ce certificat doit être reconnu par les machines qui vont se connecter à Loki (donc chaque agent Promtail).
J’en profite aussi pour rajouter le https
dans l’URL de Loki dans Grafana.
Générer un certificat pour Grafana
Je vais générer un certificat pour Grafana de la même manière que celui pour Loki:
mkcert -cert-file grafana.monitoring.une-pause-cafe.fr.crt -key-file grafana.monitoring.une-pause-cafe.fr.key grafana.monitoring.une-pause-cafe.fr grafana
Je crée un dossier /etc/grafana/ssl
sur le serveur Grafana et j’y déplace les fichiers grafana.monitoring.une-pause-cafe.fr.crt
et grafana.monitoring.une-pause-cafe.fr.key
.
scp grafana.monitoring.une-pause-cafe.fr.crt grafana.monitoring.une-pause-cafe.fr.key grafana.monitoring.une-pause-cafe.fr:/etc/grafana/ssl
Je m’assure que les certificats aient bien les permissions adéquates:
chmod 600 /etc/grafana/ssl/*
chown grafana:grafana /etc/grafana/ssl/*
Je vais ensuite modifier le fichier de configuration de Grafana pour lui indiquer d’utiliser ces certificats (dans /etc/grafana/grafana.ini
):
# [...]
[server]
protocol = https
cert_file = /etc/grafana/ssl/grafana.monitoring.une-pause-cafe.fr.crt
cert_key = /etc/grafana/ssl/grafana.monitoring.une-pause-cafe.fr.key
# [... ]
Après un redémarrage, je peux vérifier que le chiffrement est bien en place via mon navigateur :
Utiliser un S3
Nous avons vu plus haut qu’il était obligatoire d’utiliser un stockage objet pour avoir une haute disponibilité avec Loki. Il est possible de passer par des services cloud comme S3, GCS, ou Azure Blob Storage, mais je vais utiliser Minio pour stocker les logs chez moi. Je vais donc m’installer une instance Minio, un serveur de stockage objet open source compatible avec l’API S3.
La machine sur laquelle je vais installer Minio sera minio.monitoring.une-pause-cafe.fr
.
Installation de Minio
L’installation de Minio peut se faire via le fichier .deb
disponible sur le site officiel. Je vais télécharger ce fichier et l’installer via dpkg
:
wget https://dl.min.io/server/minio/release/linux-amd64/minio_20240206213622.0.0_amd64.deb
dpkg -i minio_20240206213622.0.0_amd64.deb
Minio est installé mais il nous faut encore le configurer. Pour se faire, je vais créer un fichier /etc/default/minio
avec le contenu suivant:
MINIO_VOLUMES=/mnt/data
MINIO_ROOT_USER="quentinj"
MINIO_ROOT_PASSWORD="ItsAlwaysTimeForCoffee"
MINIO_OPTS="--console-address :9001"
Je vais aussi créer l’utilisateur minio-user
(déjà utilisé dans le service installé via le deb) et lui donner les permissions sur le dossier /mnt/data
:
adduser --system --no-create-home --group minio-user
chown minio-user:minio-user /mnt/data
Je démarre ensuite le service Minio :
systemctl enable --now minio
L’adresse de la console est accessible à l’URL http://minio.monitoring.une-pause-cafe.fr:9001
. Je vais m’y connecter avec les identifiants quentinj
et ItsAlwaysTimeForCoffee
.
Avant toute chose, je vais créer un couple de clés Access/Secret key (pour m’authentifier sur l’API).
- Access key :
nxWo1sZ90TLasqUTydCs
- Secret key :
pHV1oz2m3QtYihk2KuetaxF4xGDBUOFpYTxhzWYT
Configurer le TLS pour Minio
Je vais générer un certificat wildcard pour Minio de la même manière que pour Loki et Grafana:
Information
Un wildcard est un certificat qui est valide pour un domaine et tous ses sous-domaines. Dans mon cas, le certificat sera valide pour *.minio.monitoring.une-pause-cafe.fr.
mkcert -cert-file minio.monitoring.une-pause-cafe.fr.crt -key-file minio.monitoring.une-pause-cafe.fr.key minio.monitoring.une-pause-cafe.fr '*.minio.monitoring.une-pause-cafe.fr' minio
Pourquoi un certificat en wildcard ?
Parce que lorsqu’on utilise l’API S3, on rajoute le nom du bucket comme un sous domaine de l’URL. Par exemple, pour accéder au bucket loki
, on utilise l’URL https://loki.minio.monitoring.une-pause-cafe.fr:9000
. Si le certificat n’est valide que pour minio.monitoring.une-pause-cafe.fr
, le client S3 va afficher une erreur de certificat.
Je crée un dossier /opt/minio/certs
sur la machine Minio et j’y déplace les fichiers minio.monitoring.une-pause-cafe.fr.crt
et minio.monitoring.une-pause-cafe.fr.key
.
scp minio.monitoring.une-pause-cafe.fr.crt minio.monitoring.une-pause-cafe.fr.key minio.monitoring.une-pause-cafe.fr:/opt/minio/certs
Je dois aussi renommer ces fichiers en private.key
et public.crt
:
mv /opt/minio/certs/minio.monitoring.une-pause-cafe.fr.crt /opt/minio/certs/public.crt
mv /opt/minio/certs/minio.monitoring.une-pause-cafe.fr.key /opt/minio/certs/private.key
Je m’assure que seul l’utilisateur minio-user
ait accès à ces fichiers :
chown minio-user:minio-user /opt/minio/certs/*
chmod 600 /opt/minio/certs/*
J’édite le fichier /etc/default/minio
pour rajouter le chemin vers les certificats :
MINIO_VOLUMES=/mnt/data
MINIO_ROOT_USER="quentinj"
MINIO_ROOT_PASSWORD="ItsAlwaysTimeForCoffee"
MINIO_OPTS="--console-address :9001 --certs-dir /opt/minio/certs"
Un petit systemctl restart minio
et j’accède bien à la console en TLS !
$ curl -I https://minio.monitoring.une-pause-cafe.fr:9001
HTTP/2 200
accept-ranges: bytes
content-security-policy: default-src 'self' 'unsafe-eval' 'unsafe-inline';
content-type: text/html
last-modified: Thu, 08 Feb 2024 18:04:41 GMT
referrer-policy: strict-origin-when-cross-origin
server: MinIO Console
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
content-length: 1310
Créer un bucket pour Loki (avec MC)
MC est un client en ligne de commande pour Minio. Il permet de manipuler notre instance Minio de manière simple et efficace. Nous allons l’utiliser pour créer notre bucket pour Loki.
Je l’installe sur mon poste local en téléchargeant le binaire:
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin
Je vais ensuite configurer MC pour qu’il se connecte à mon instance Minio avec les clés que j’ai générées plus tôt:
$ mc alias set homelab-monitoring/ https://minio.monitoring.une-pause-cafe.fr:9000 nxWo1sZ90TLasqUTydCs "pHV1oz2m3QtYihk2KuetaxF4xGDBUOFpYTxhzWYT"
Added `homelab-monitoring` successfully.
Avertissement
- ⚠️ Attention, le port utilisé pour
mc
est le:9000
et non le:9001
. - Il est aussi possible d’utiliser les mêmes identifiants que ceux utilisés pour l’API S3 (dans mon cas,
quentinj
etItsAlwaysTimeForCoffee
), mais je vous recommande de créer des identifiants spécifiques pour chaque service.
Je vais ensuite créer un bucket pour Loki:
$ mc mb homelab-monitoring/loki
Bucket created successfully `homelab-monitoring/loki`.
Configurer Loki pour utiliser un S3
Je vais modifier le fichier de configuration de Loki pour lui indiquer d’utiliser Minio comme stockage objet pour la persistance des logs.
auth_enabled: false
server:
http_listen_port: 3100
http_tls_config:
cert_file: /etc/loki/ssl/loki-01.monitoring.une-pause-cafe.fr.crt
key_file: /etc/loki/ssl/loki-01.monitoring.une-pause-cafe.fr.key
ingester:
wal:
enabled: true
dir: /tmp/loki/wal
chunk_idle_period: 5m
chunk_retain_period: 30s
chunk_block_size: 262144
chunk_encoding: snappy
compactor:
working_directory: /tmp/loki/compactor
shared_store: s3
compaction_interval: 5m
retention_enabled: true
schema_config:
configs:
- from: 2020-05-15
store: boltdb-shipper
object_store: s3
schema: v11
index:
prefix: index_
period: 24h
common:
replication_factor: 1
path_prefix: /tmp/loki
storage_config:
boltdb_shipper:
active_index_directory: /tmp/loki/index
cache_ttl: 24h
cache_location: /tmp/loki/index_cache
resync_interval: 5s
shared_store: s3
aws:
s3: "https://nxWo1sZ90TLasqUTydCs:pHV1oz2m3QtYihk2KuetaxF4xGDBUOFpYTxhzWYT@minio:9000/loki"
s3forcepathstyle: true
bucketnames: loki
region: us-east-1
access_key_id: "nxWo1sZ90TLasqUTydCs" # Le compactor a besoin de ces variables pour fonctionner
secret_access_key: "pHV1oz2m3QtYihk2KuetaxF4xGDBUOFpYTxhzWYT"
endpoint: "https://minio.monitoring.une-pause-cafe.fr:9000"
Avec cette configuration, Loki va stocker ses logs en local et le compactor va les envoyer sur Minio pour les stocker de manière persistante.
Information
Le compactor est un composant de Loki qui est responsable de la compaction des logs. Il est nécessaire pour garder une taille raisonnable de la base de données de Loki. Il se charge aussi de faire de la déduplication des logs pour économiser de l’espace disque.
Cluster Loki
Loki supporte le clustering, c’est-à-dire qu’il est possible de lancer plusieurs instances de Loki pour avoir une haute disponibilité. La documentation officielle explique qu’un setup de production se fait dans un Kubernetes, mais je vais essayer de le faire sur mes machines virtuelles.
Les nœuds du cluster vont dialoguer via un Gossip Ring
, un protocole de communication permettant à chaque nœud de partager des informations avec les autres.
Information
Comme vu plus haut, il convient d’utiliser un stockage objet pour la persistance des logs, le stockage local ne supportant pas le clustering. Le passage par le stockage objet était donc obligatoire pour la suite de cet article.
Je vais installer Loki sur deux autres machines, loki-02.monitoring.une-pause-cafe.fr
et loki-03.monitoring.une-pause-cafe.fr
pour avoir un cluster de trois nœuds.
Voici le fichier de configuration que j’ai utilisé pour les nœuds (en dehors des certificats à remplacer) :
auth_enabled: false
server:
http_listen_port: 3100
http_tls_config:
cert_file: /etc/loki/ssl/loki-01.monitoring.une-pause-cafe.fr.crt # <---- Certificat à remplacer
key_file: /etc/loki/ssl/loki-01.monitoring.une-pause-cafe.fr.key # <---- Clé privée à remplacer
grpc_server_max_recv_msg_size: 20971520
grpc_server_max_send_msg_size: 20971520
distributor:
ring:
kvstore:
store: memberlist
ingester:
wal:
enabled: true
dir: /tmp/loki/wal
lifecycler:
ring:
kvstore:
store: memberlist
replication_factor: 1
final_sleep: 0s
chunk_idle_period: 5m
chunk_retain_period: 30s
chunk_block_size: 262144
chunk_encoding: snappy
compactor:
working_directory: /tmp/loki/compactor
shared_store: s3
compaction_interval: 5m
retention_enabled: true
memberlist:
abort_if_cluster_join_fails: false
bind_port: 7946
join_members:
- loki-01:7946
- loki-02:7946
- loki-03:7946
max_join_backoff: 1m
max_join_retries: 10
min_join_backoff: 1s
schema_config:
configs:
- from: 2020-05-15
store: boltdb-shipper
object_store: s3
schema: v11
index:
prefix: index_
period: 24h
common:
ring:
instance_addr: 127.0.0.1
kvstore:
store: memberlist
replication_factor: 3
path_prefix: /tmp/loki
storage_config:
boltdb_shipper:
active_index_directory: /tmp/loki/index
cache_ttl: 168h
cache_location: /tmp/loki/index_cache
resync_interval: 5s
shared_store: s3
aws:
s3: "https://nxWo1sZ90TLasqUTydCs:pHV1oz2m3QtYihk2KuetaxF4xGDBUOFpYTxhzWYT@minio:9000/loki"
s3forcepathstyle: true
bucketnames: loki
region: us-east-1 # <---- pour Minio, c'est la région par défaut
access_key_id: "nxWo1sZ90TLasqUTydCs"
secret_access_key: "pHV1oz2m3QtYihk2KuetaxF4xGDBUOFpYTxhzWYT"
endpoint: "https://minio.monitoring.une-pause-cafe.fr:9000"
Je vais redémarrer Loki sur les trois machines pour que le clustering soit effectif.
févr. 10 09:38:31 loki-02 loki[2812]: level=info ts=2024-02-10T08:38:31.839709692Z caller=memberlist_client.go:592 msg="joining memberlist cluster succeeded" reached_nodes=2 elapsed_time=8.0811ms
Sur Loki-02, je vois bien que le nœud a rejoint le cluster ⬆️ !
Vous savez comment on peut vérifier l’état du cluster ? Avec du PromQL sur un Prometheus, bien sûr (Puisque c’est de la supervision) !
Voici la configuration que j’ai ajoutée à mon fichier de configuration de Prometheus pour qu’il scrape les métriques de Loki:
- job_name: loki
scrape_interval: 5s
scheme: "https"
scrape_timeout: 5s
static_configs:
- targets: ['loki-01.monitoring.une-pause-cafe.fr:3100', 'loki-02.monitoring.une-pause-cafe.fr:3100', 'loki-03.monitoring.une-pause-cafe.fr:3100']
On peut afficher l’état du cluster avec la requête suivante:
{__name__=~"loki_memberlist_.*cluster.*"}
(un node_health
à 0 veut dire que le nœud est Healthy.)
Mais concrètement, qu’est-ce que ça change pour le moment ? Promtail envoie toujours ses logs à Loki-01, qui les stocke sur Minio.
La prochaine étape est d’installer une VIP (Virtual IP) pour que Promtail envoie ses logs à la VIP, qui les répartira sur un des nœuds du cluster. Mais avant ça, nous pouvons d’ores et déjà vérifier du bon fonctionnement du clustering en redirigeant les requêtes des Promtails vers loki-02
, puis interrogeant loki-01
et loki-02
pour voir si les logs sont bien accessibles sur les deux nœuds.
$ logcli query '{job="nginx"} |= `UneTasseDeCafe`' --addr="https://loki-01.monitoring.une-pause-cafe.fr:3100"
2024/02/13 18:22:34 https://loki-01.monitoring.une-pause-cafe.fr:3100/loki/api/v1/query_range?direction=BACKWARD&end=1707844954515007056&limit=30&query=%7Bjob%3D%22nginx%22%7D+%7C%3D+%60UneTasseDeCafe%60&start=1707841354515007056
2024/02/13 18:22:34 Common labels: {filename="/var/log/nginx/access.log", job="nginx", node="grafana"}
2024-02-13T18:18:48+01:00 {} 100.64.0.13 - - [13/Feb/2024:18:18:48 +0100] "GET /UneTasseDeCafe HTTP/1.1" 404 125 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0"
$ logcli query '{job="nginx"} |= `UneTasseDeCafe`' --addr="https://loki-02.monitoring.une-pause-cafe.fr:3100"
2024/02/13 18:22:38 https://loki-02.monitoring.une-pause-cafe.fr:3100/loki/api/v1/query_range?direction=BACKWARD&end=1707844958725211857&limit=30&query=%7Bjob%3D%22nginx%22%7D+%7C%3D+%60UneTasseDeCafe%60&start=1707841358725211857
2024/02/13 18:22:39 Common labels: {filename="/var/log/nginx/access.log", job="nginx", node="grafana"}
2024-02-13T18:18:48+01:00 {} 100.64.0.13 - - [13/Feb/2024:18:18:48 +0100] "GET /UneTasseDeCafe HTTP/1.1" 404 125 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0"
Les mêmes données sont bien présentes sur les deux nœuds du cluster !
Maintenant, passons à la mise en place de la VIP.
Mise en place de la VIP
La VIP est un point d’entrée unique pour les clients. Elle va répartir les requêtes entrantes sur un des nœuds fonctionnels du cluster. J’utilise keepalived
pour mettre en place la VIP.
Sur chacun des nœuds du cluster, je vais installer keepalived
:
apt install keepalived -y
Je vais ensuite créer un fichier /etc/keepalived/keepalived.conf
sur loki-01
avec le contenu suivant:
vrrp_instance VI_1 {
state MASTER
interface ens18
virtual_router_id 51
priority 255
advert_int 1
authentication {
auth_type PASS
auth_pass CoffeeAddict
}
virtual_ipaddress {
192.168.1.5/24
}
}
Avertissement
⚠️ Attention, l’interface ens18
est spécifique à ma machine. Vous devez remplacer ens18
par l’interface réseau de votre machine.
L’usage du auth_pass CoffeeAddict
est aussi un exemple, vous devez le remplacer par un mot de passe sécurisé (et le même sur tous les nœuds) ou utiliser un autre mode d’authentification.
Sur les autres nœuds, je vais créer ce même fichier, mais avec state BACKUP
et une priorité plus faible.
vrrp_instance VI_1 {
state BACKUP
interface ens18
virtual_router_id 51
priority 254
advert_int 1
authentication {
auth_type PASS
auth_pass CoffeeAddict
}
virtual_ipaddress {
192.168.1.5/24
}
}
Je vais ensuite démarrer le service keepalived
sur les trois machines :
systemctl enable --now keepalived
l’IP 192.168.1.5
est maintenant redirigée vers loki-01
. Si ce nœud tombe, la VIP sera redirigée vers une autre machine du cluster.
Je vais créer l’entrée DNS loki.monitoring.une-pause-cafe.fr
pour pointer vers cette VIP et créer le certificat pour cette adresse.
$ mkcert -cert-file loki.monitoring.une-pause-cafe.fr.crt -key-file loki.monitoring.une-pause-cafe.fr.key loki.monitoring.une-pause-cafe.fr loki
Je vais ensuite déplacer ces fichiers dans /etc/loki/ssl
sur loki-01
et les copier sur les autres nœuds.
scp loki.monitoring.une-pause-cafe.fr.crt loki.monitoring.une-pause-cafe.fr.key loki-01.monitoring.une-pause-cafe.fr:/etc/loki/ssl
scp loki.monitoring.une-pause-cafe.fr.crt loki.monitoring.une-pause-cafe.fr.key loki-02.monitoring.une-pause-cafe.fr:/etc/loki/ssl
scp loki.monitoring.une-pause-cafe.fr.crt loki.monitoring.une-pause-cafe.fr.key loki-03.monitoring.une-pause-cafe.fr:/etc/loki/ssl
ssh loki-01.monitoring.une-pause-cafe.fr "chown loki /etc/loki/ssl/*"
ssh loki-02.monitoring.une-pause-cafe.fr "chown loki /etc/loki/ssl/*"
ssh loki-03.monitoring.une-pause-cafe.fr "chown loki /etc/loki/ssl/*"
Je vais ensuite modifier le fichier de configuration de Loki pour lui indiquer d’utiliser ces certificats :
ssh loki-01.monitoring.une-pause-cafe.fr "sed -i 's/loki-0[0-9].monitoring.une-pause-cafe.fr/loki.monitoring.une-pause-cafe.fr/g' /etc/loki/config.yml"
ssh loki-02.monitoring.une-pause-cafe.fr "sed -i 's/loki-0[0-9].monitoring.une-pause-cafe.fr/loki.monitoring.une-pause-cafe.fr/g' /etc/loki/config.yml"
ssh loki-03.monitoring.une-pause-cafe.fr "sed -i 's/loki-0[0-9].monitoring.une-pause-cafe.fr/loki.monitoring.une-pause-cafe.fr/g' /etc/loki/config.yml"
Je vais redémarrer le service Loki sur les trois machines pour que les changements soient pris en compte.
ssh loki-01.monitoring.une-pause-cafe.fr "systemctl restart loki"
ssh loki-02.monitoring.une-pause-cafe.fr "systemctl restart loki"
ssh loki-03.monitoring.une-pause-cafe.fr "systemctl restart loki"
Je vais ensuite modifier le fichier de configuration de Promtail pour lui indiquer d’envoyer ses logs à loki.monitoring.une-pause-cafe.fr
:
clients:
- url: https://loki.monitoring.une-pause-cafe.fr:3100/loki/api/v1/push
# [...]
Sur Grafana, je modifie la source de données Loki pour lui indiquer d’utiliser loki.monitoring.une-pause-cafe.fr
comme URL.
Une fois que tout est en place, je vais vérifier que les logs sont bien envoyés à loki.monitoring.une-pause-cafe.fr
et que les requêtes sont bien réparties sur les trois nœuds du cluster.
$ logcli query '{job="nginx"} |= `UneTasseDeCafe`' --addr="https://loki.monitoring.une-pause-cafe.fr:3100"
# [...]
2024/02/13 21:27:51 Common labels: {filename="/var/log/nginx/access.log", job="nginx", node="grafana"}
2024-02-13T21:27:48+01:00 {} 100.64.0.1 - - [13/Feb/2024:21:27:48 +0100] "GET /?UneTasseDeCafe HTTP/1.1" 200 409 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0"
2024/02/13 21:27:51 https://loki.monitoring.une-pause-cafe.fr:3100/loki/api/v1/query_range?direction=BACKWARD&end=1707856068916047554&limit=30&query=%7Bjob%3D%22nginx%22%7D+%7C%3D+%60UneTasseDeCafe%60&start=1707852471375877575
Conclusion
Nous avons vu comment mettre en place un cluster Loki avec un stockage objet, une VIP et un chiffrement TLS. Nous avons aussi vu comment superviser notre cluster avec Prometheus.
J’ai eu de grosses difficultés à mettre en place le clustering de Loki, principalement à cause de la documentation qui n’est pas très claire sur le sujet et qui est très orientée Kubernetes. J’ai un peu tâtonné pour trouver la bonne configuration.
Mine de rien, Loki est un outil beaucoup plus puissant que ce que je pensais, la documentation présente des paramètres qui peuvent vraiment être fine-grained en fonction de nos besoins. Je suis content de ce lab, j’ai appris beaucoup de choses sur Loki que j’espère pouvoir réutiliser dans le futur.
Je m’attaquerai peut-être à une installation de VictoriaLogs, une alternative à Loki qui est plus orientée performance (Elastic a aussi une solution similaire, mais j’ai peur des ressources demandés dans une configuration ‘minimale’).
En espérant que ce lab vous ait plu, je vous dis à bientôt pour un prochain article !