Sommaire
Un mot sur Prometheus
Afin de bien comprendre le fonctionnement de Loki, il est important de comprendre celui de Prometheus. Le lecteur est invité à lire une publication précédente dans ces colonnes : Découverte de l’outil de supervision Prometheus. Même si le produit a évolué entretemps (la version 2.0.0 venait de sortir), ce qui est écrit reste tout à fait valable avec la dernière version (2.14).
La caractéristique de ce produit est de récupérer des métriques en provenance de points de collecte (on parle d’exporteur) et de les stocker dans une base de données de type Time Series en y ajoutant des métadonnées sous forme de labels.
Origine du besoin
Ces derniers temps, Prometheus est devenu un standard de fait dans le monde de Kubernetes : son installation est très simple à réaliser et l’ensemble des briques d’un cluster Kube dispose nativement d’un endpoint Prometheus. Le moteur Prometheus est également en mesure de récupérer des métriques en provenance des applications déployées dans ce type de cluster tout en reprenant les labels définis. La surveillance des consommations applicatives est donc très simple à mettre en oeuvre.
Malheureusement, du côté des logs, il n’y a pas encore de méthode clé en main et l’utilisateur doit trouver sa propre solution :
- un service géré de centralisation des logs dans le cloud (AWS, Azure ou Google) ;
- un service de monitoring as a service (type Datadog) ;
- la mise en place d’un service de centralisation.
Au niveau de la troisième solution, votre serviteur avait traditionnellement l’habitude de mettre en place Elasticsearch, avec de nombreuses réserves à propos de ce produit notamment sur sa lourdeur et la difficulté de sa mise en place.
Loki a justement été conçu dans le but de simplifier cette mise en place en répondant aux critères suivants :
- être un produit simple à démarrer ;
- consommer peu de ressources ;
- fonctionner tout seul sans intervention de maintenance particulière ;
- servir de support à l’investigation en complément de Prometheus en cas de pépin.
En revanche, cette légèreté se fait au prix de certains compromis. L’un d’eux est de ne faire aucune indexation du contenu. La recherche de texte n’est donc de ce point de vue pas très performante ni très riche et ne permet pas de faire des statistiques sur le contenu du texte. Mais comme Loki se veut être un équivalent de grep et doit servir de complément à Prometheus, ce défaut n’en est pas un.
Méthode de résolution d’incidents
Pour mieux comprendre en quoi Loki n’a pas besoin d’indexation, nous allons revenir sur la méthode utilisée par les concepteurs de Loki avec le schéma suivant :
1- Alert → 2- Dashboard → 3 Adhoc Query → 4 Log Aggregation → 5 Distributed Tracing → 6 Fix!
L'idée est de partir d'une source d'alerte (notification Slack, SMS, etc.). La personne en charge du suivi fait alors la démarche suivante :
- consultation des tableaux de bords Grafana ;
- consultation des métriques brutes (dans Prometheus par exemple) ;
- consultation des logs (Elasticsearch par exemple) ;
- éventuellement, consultation des traces distribuées (Jaeger, Zipkin, etc.) ;
- enfin, correction du dysfonctionnement.
Ici, dans le cas d’un empilement (stack) Grafana + Prometheus + Elasticsearch + Zipkin, l’utilisateur devra changer quatre fois d’outils. Afin de réduire les temps d’intervention, l’idée est de tout faire avec un seul outil : Grafana. À noter que Grafana propose cette notion d’exploration depuis la version 6. Il devient ainsi possible de consulter les données brutes de Prometheus directement depuis Grafana.
Depuis cet écran il est possible de consulter les logs de Loki associés aux métriques de Prometheus notamment en faisant appel à la notion de découpage de l’écran. On imagine très bien qu’une fois que Loki aura été correctement intégré dans Grafana, la suite des travaux se fera sûrement sur l’intégration de Grafana et des outils de traces distribuées.
Test de Loki en local
Le plus simple pour tester Loki en local est de passer par Docker et l’outil docker-compose.
Le fichier docker-compose se trouve sur le dépôt de Loki. La récupération du contenu de ce dépôt se fait à l’aide de la commande git suivante :
git clone https://github.com/grafana/loki.git
Reste ensuite à se rendre dans le répertoire production :
cd production
De là, il est possible de récupérer la dernière version des images Docker :
docker-compose pull
Enfin, la stack de Loki se lance à l'aide de la commande suivante :
docker-compose up
Architecture de Loki
Un petit dessin valant toujours mieux qu’un long discours, ci-dessous un petit schéma de principe de Loki :
Un client web fait tourner des applications sur le serveur, Promtail en collecte les logs qu'il envoie à Loki, le client web envoie aussi des méta+données à Loki. Loki agrège le tout et transmet à Grafana.
Loki est démarré. Afin de consulter les composants présents, lancez la commande suivante :
docker ps
Dans le cas d’un démon Docker fraîchement installé, la commande doit alors renvoyer la sortie suivante :
... IMAGE ... PORTS NAMES
... grafana/promtail:... production_promtail_1
... grafana/grafana:m... 0.0.0.0:3000->3000/tcp production_grafana_1
... grafana/loki:late... 80/tcp, 0.0.0.0:3100->3100/tcp production_loki_1
On retrouve les briques suivantes :
- Promtail : un agent qui prend en charge la centralisation des logs (Promtail, pour Tailing logs in Prometheus format) ;
- Grafana : le célèbre outil de mise en page des données ;
- Loki : le démon de centralisation des données.
Dans le cadre d’une installation sur infrastructure classique (à base de machine virtuelle par exemple), l’agent Promtail devra être déployé sur chaque machine. Grafana et Loki pourront être éventuellement installés sur la même machine.
Déploiement dans Kubernetes
L’installation des briques de Loki dans Kubernetes va s’appuyer sur les éléments suivants :
- un gestionnaire de démon (DaemonSet) pour déployer l’agent Promtail sur chacune des machines du cluster ;
- un déploiement (Deployment) pour déployer la partie Loki ;
- et un dernier déploiement pour Grafana.
Par chance, Loki est disponible sous forme de paquet Helm afin de simplifier son déploiement.
Installation de Helm
Pour la suite, l’utilisateur devra disposer de la commande helm
. Cette dernière se récupère sur le dépôt GitHub du projet. Charge à l’utilisateur de décompresser l’archive correspondante à l’architecture du poste de l’utilisateur et de placer la commande helm
dans $PATH.
NB : La version 3.0.0 de Helm vient juste de sortir. Étant donné qu’elle change beaucoup de choses, il est conseillé au lecteur d’attendre un peu avant de s’y mettre.
Ajout de la source Helm
La première étape va consister à ajouter le dépôt « loki » à l’aide de la commande suivante :
helm repo add loki https://grafana.github.io/loki/charts
Une fois cette commande lancée, il devient possible de chercher les paquets portant le nom loki :
helm search loki
Ci-dessous un exemple de résultat renvoyé :
loki/loki 0.17.2 v0.4.0 Loki: like Prometheus, but for logs.
loki/loki-stack 0.19.1 v0.4.0 Loki: like Prometheus, but for logs.
loki/fluent-bit 0.0.2 v0.0.1 Uses fluent-bit Loki go plugin for gathering logs and sen...
loki/promtail 0.13.1 v0.4.0 Responsible for gathering logs and sending them to Loki
Ces paquets ont différentes fonctions :
- le paquet loki/loki correspond au serveur Loki seul ;
- le paquet loki/fluent-bit permet de déployer un DaemonSet s’appuyant sur fluent-bin pour centraliser les logs à la place de Promtail ;
- le paquet loki/promtail contenant l’agent de centralisation des journaux d’activités ;
- le paquet loki/loki-stack permettant de déployer Loki et Promtail en une seule fois.
Déploiement de Loki
Afin de déployer Loki dans Kubernetes, dans l’espace de nom « monitoring », lancez la commande suivante :
helm upgrade --install loki loki/loki-stack --namespace monitoring
Pour disposer d’un espace disque persistant, ajoutez l’option --set loki.persistence.enabled=true
:
helm upgrade --install loki loki/loki-stack --namespace monitoring --set loki.persistence.enabled=true
Remarque : dans le cas où vous souhaiteriez déployer grafana en même temps, ajouter l’option --set grafana.enabled=true
.
Au lancement de cette commande, l’utilisateur devrait obtenir la sortie suivante :
LAST DEPLOYED: Tue Nov 19 15:56:54 2019
NAMESPACE: monitoring
STATUS: DEPLOYED
RESOURCES:
==> v1/ClusterRole
NAME AGE
loki-promtail-clusterrole 189d
...
NOTES:
The Loki stack has been deployed to your cluster. Loki can now be added as a datasource in Grafana.
See http://docs.grafana.org/features/datasources/loki/ for more detail.
Un coup d’œil sur l’état des pods de l’espace de nom « monitoring » terminera de nous indiquer que tout est déployé :
kubectl -n monitoring get pods -l release=loki
Ci-dessous un exemple de résultat renvoyé :
NAME READY STATUS RESTARTS AGE
loki-0 1/1 Running 0 147m
loki-promtail-9zjvc 1/1 Running 0 3h25m
loki-promtail-f6brf 1/1 Running 0 11h
loki-promtail-hdcj7 1/1 Running 0 3h23m
loki-promtail-jbqhc 1/1 Running 0 11h
loki-promtail-mj642 1/1 Running 0 62m
loki-promtail-nm64g 1/1 Running 0 24m
Tous les pods sont démarrés. Il est maintenant temps de faire quelques tests !
Connexion à Grafana
Sous Kubernetes, afin de pouvoir se connecter à Grafana, il est nécessaire d’ouvrir un tunnel vers son pod. Ci-dessous la commande permettant d’ouvrir le port 3000 vers le pod de Grafana :
kubectl -n monitoring port-forward svc/loki-grafana 3000:80
Autre point important, la nécessité de récupérer le mot de passe de l’administrateur de Grafana. Ce dernier est stocké dans le secret loki-grafana dans le champ .data.admin-user au format base64.
Afin de le récupérer, lancez la commande suivante :
kubectl -n monitoring get secret loki-grafana --template '{{index .data "admin-password"|base64decode}}' ; echo
Utilisez ce mot de passe conjointement avec le compte d’administration par défaut (admin).
Définition datasource loki depuis Grafana
Première chose à faire, s’assurer que le datasource de Loki est bien présent (se rendre à l’emplacement suivant : Configuration / Datasource).
Voici un exemple de définition valide :
Un clic sur le bouton Test permettra de s’assurer que la communication avec Loki se passe bien.
Interrogation du moteur Loki
Rendez-vous maintenant dans le champ « Explorer » de Grafana. Au moment de l’ingestion des logs des containers, Loki se charge d’ajouter les annotations en provenance de Kubernetes. Il devient ainsi possible de s’en servir pour récupérer les logs d’un container spécifique.
Ainsi, pour sélectionner les logs des containers promtail, la requête à rentrer sera la suivante : {container_name="promtail"}
. Pensez également à bien sélectionner la source de données de Loki.
Cette requête renverra alors l’activité de ces containers sous la forme suivante :
Inclusion dans un dashboard
Depuis la version 6.4 de Grafana, il est possible d’inclure un extrait des logs dans un tableau de bord Grafana. L’utilisateur peut alors rapidement mettre en parallèle les courbes de fréquentation de son site avec les traces renvoyées par son application.
Ci-dessous un exemple de tableau de bord réalisant ce mélange :
Futur de Loki
Lorsque j’ai commencé à écrire cet article en août, la version 0.3 de Loki venait à peine de sortir. La sortie de la version 1.0 est en quelque sorte la raison qui m’a poussé à finir mon travail :)
J’ai commencé à l’utiliser à partir de la version 0.1 et il faut bien avouer qu’à l’époque la stabilité n’était pas encore au rendez-vous. Globalement, la version 0.3 a apporté de vrais signes de maturité et les versions suivantes (0.4 puis 1.0) n’ont fait que conforter cette impression.
Dorénavant avec la version 1.0.0, plus personne ne devrait avoir d’excuse pour ne pas utiliser cet excellent outil.
Les travaux les plus intéressants ne devraient plus avoir lieu sur Loki mais plus sur l’intégration avec l’excellent Grafana. En effet, la version 6.4 de Grafana a apporté une bonne intégration avec les tableaux de bords.
La version 6.5 qui vient juste de sortir améliore encore cette intégration en permettant de convertir automatiquement le contenu de la ligne de log lorsqu’elle est au format JSON.
Ci-dessous une petite vidéo présentant ce mécanisme :
Il devient aussi possible d’utiliser un des champs de la structure JSON pour par exemple :
- pointer vers un outil externe ;
- filtrer le contenu des logs.
On peut alors cliquer sur le champ traceId afin de pointer vers un tableau de bord de Zipkin ou Jaeger.