Elastic monitoring pour les Nuls - Part 2 ( "Make Some Beat")

Dans la continuité de l'article précédent, je vais cette fois-ci montrer comment il est possible de superviser les métriques d'un ordinateur, plus proprement. La brique Kafka est enlevée afin de se concentrer sur Elastic. Cette fois-ci nous écrirons par Elastic Beats pour la collecte des données, afin de créer une solution 100% Elastic. Le code de ce projet est disponible ici.

Pour notre use case, Metricbeat existe déjà, c'est un outil parfaitement adapté, facile d'installation et complet. Cet article a pour but de comprendre comment développer son propre Beat.

Elastic Beats, mais pour quoi faire ?

La stack initiale d'Elastic était composée de Elasticsearch, Logstash et Kibana. Aujourd'hui le terme ELK n'est plus d'actualité car Elastic a sorti d'autres produits complétant cette stack. Elle est désormais dénommée Elastic Stack. Elastic Beats en fait partie.

Beats est un ensemble d'outils permettant de collecter des données et de les envoyer vers Elasticsearch ou Logstash si le besoin de transformer les données est présent. Une fois installé et lancé sur une machine, un daemon Beats s'exécute en tâche de fond et est totalement transparent pour l'utilisateur.

Beats est open-source et chacun peut créer le sien. Aujourd'hui il en existe une multitude déjà créés, constamment maintenus et aussi très complets. Les plus courants font partie de ce qui est appelé la "Beats Family". Il est donc fortement conseillé d'utiliser ces Beats déjà mis à disposition.

Néanmoins, il n'est pas rare que l'existant ne soit pas suffisant ou ne réponde pas à nos problématiques. C'est pourquoi dans cet article nous allons créer notre propre Beat en utilisant les outils mis à disposition par Elastic. Celui-ci enverra directement les métriques (CPU, RAM…) vers Elasticsearch.

En lisant la documentation, j'ai appris que les Beats étaient développés avec Go. J'en avais déjà entendu parlé mais ma connaissance s'arrêtait à leur ancien logo rat (le Gopher). Heureusement, il n'est pas nécessaire de comprendre tous les concepts du Go pour développer son Beat.

Go est un langage compilé, ce qui l'oppose aux langages interprétés (e.g Python). Pour avoir une courte introduction au Go je vous conseille ces pages :

  • How to write Go code : explique le fonctionnement du Go, la hiérarchie à respecter lors de l'écriture de code et aussi comment l'utiliser une fois écrit. Une particularité du Go étant la gestion de la mémoire manuelle (#TeamC) au côté d'un Garbage Collector (#TeamJava). Son mode asynchrone natif lui a aussi permis de se faire des adeptes.
  • Learn X in Y minutes, Go : explique comment coder en Go, la syntaxe et les spécificités du langage. Ce site est souvent bien fait pour tout développeur souhaitant apprendre un nouveau langage ou se remémorer des syntaxes.
  • A Tour Of Go: permet de s'entraîner à développer en ligne.

Tip : À ajouter dans .zshrc ou .bashrc :

export PATH = $PATH:/usr/local/go/bin

Pour suivre ce tuto il est aussi nécessaire d'installer Python (v2.7.X ) et virtualenv.

Création du Beat

La création d'un Beat (v6.6) en suivant la documentation présente sur le dépôt GitHub n'est pas un long fleuve tranquille. En effet, certaines informations présentes sur les tutoriels fournis peuvent être obsolètes.

Pour créer un Beat il faut d'abord installer Go sur son poste, et faire pointer la variable d'environnement $GOPATH sur le workspace Go. Il faut ajouter au fichier de configuration .zshrc (.bashrc) :

export GOPATH = $(go env GOPATH)

Une fois fait, il faut cloner le dépôt GitHub de Beat dans le bon dossier, attention à la hiérarchie Go à respecter !

$ mkdir -p ${GOPATH}/src/github.com/elastic
$ git clone https://github.com/elastic/beats ${GOPATH}/src/github.com/elastic/beats

Ce dépôt contient des Beats de la "Beats Family" et aussi Libbeat qui contient toute la structure nécessaire pour avoir un Beat qui fonctionne. La base Libbeat va nous être utile pour écrire le nôtre. Le fonctionnement est le suivant :

alt_text

La brique Beat Custom Logic se charge de récupérer les données et les envoie au Publisher sous forme d'Events. C'est ce dernier qui enverra les données vers un Logstash ou Elasticsearch. Lorsque l'on souhaite développer son propre Beat, la logique de l'application est située dans Beat Custom Logic qui construit les bonnes données sous format JSON. Cette donnée doit à minima contenir un champ "@timestamp".

Voilà pour la théorie, désormais il faut créer son propre dossier pour le Beat, que l'on appellera Bonbeat.

$ mkdir ${GOPATH}/src/github.com/{user} #user Github
$ cd ${GOPATH}/src/github.com/{user}

Avant de générer notre projet Beat, il faut changer une ligne dans le code d'origine. si cette ligne n'est pas modifiée (dans la version actuelle de Beats), un bug bloquant empêche la suite du développement. La ligne 15 dans le Makefile situé_ ${GOPATH}/src/github.com/elastic/beats/libbeat/scripts_ est à modifier:

ES_BEATS?=.. → ES_BEATS?=./vendor/github.com/elastic/beats

On va désormais lancer un script Python pour générer toute l'architecture de ce nouveau Beat.

$ python $GOPATH/src/github.com/elastic/beats/script/generate.py
Beat Name [Examplebeat]: Bonbeat
Your Github Name [your-github-name]: lukland
Beat Path [github.com/lukland/bonbeat]: 
Firstname Lastname: Harry Cover

Disclaimer: Il faut avoir la version 2 de Python, ceci n'est pas une blague…

Notre nouveau beat est désormais créé, avec des fichiers Go et Makefile un peu partout.

Il faut setter le virtual-environnement puis lancer la partie setup du make. La dernière commande permet de générer l'exécutable du Beat :

$ cd ${GOPATH}/src/github.com/lukland/bonbeat
$ virtualenv -p python build/python-env 
$ make build
$ go build

Une fois la stack ELK déployée (docker-compose up --build), le Beat est prêt à être exécuté:

$ ./bonbeat -e -d "*"      

À partir de maintenant, nous avons un Bonbeat fonctionnel. Il ne reste plus qu'à remonter les données intéressantes.

Le fichier à modifier est le bonbeat.go situé dans src/github.com/lucaslandry/bonbeat/beater/. C'est dans la fonction Run(b *beat.Beat) que se crée l'event qui sera envoyé au producer. Pour récupérer les métriques à intégrer dans l'event je suis passé par la librairie gopsutil.

Ne pas oublier d'importer la librairie dans la définition des imports.

 $ go get github.com/shirou/gopsutil 

Afin d'envoyer le pourcentage de RAM utilisée, il faut modifier la boucle infinie du Run :

...
ticker := time.NewTicker(bt.config.Period)
for {
		select {
		case <-bt.done:
			return nil
		case <-ticker.C:
		}
		v, _ := mem.VirtualMemory()

		event := beat.Event{
			Timestamp: time.Now(),
			Fields: common.MapStr{
				"type":    b.Info.Name,
				"memory_used_percent": v.UsedPercent,
			},
		}
		bt.client.Publish(event)
}
...

Il ne reste plus qu'à récupérer et inclure dans l'event les métriques qui nous intéressent. Le fichier JSON envoyé ressemblera dans ce cas à :

{
  "@timestamp": "2019-01-09T12:49:41.487Z",
  "@metadata": { ... },
  "host": { ... },
  "ecs": { ... },
  "agent": { ... },
  "type": "MBP-de-Luk.localdomain",
  "memory_used_percent": 56.31279945373535
}

Ici les logs sont envoyés directement à Elasticsearch mais si on souhaite passer par Logstash pour filtrer/transformer les données, il faut modifier le document bonbeat.yml situé à la racine du projet. Il suffit alors de décommenter les lignes en rapport avec Logstash.

Well done! Vous avez développé un Beat remontant les métriques de votre ordinateur.

Conclusion

Elastic Beats est un outil puissant et nous a permis de faire un shipper personnel assez rapidement, notamment grâce au générateur.

Néanmoins, en suivant la documentation on est vite bloqué. Et n'étant pas connaisseur de Go et très peu de Makefile, je me suis bien creusé la tête avant d'avoir un résultat. Je trouve dommage que la documentation actuelle pour cette partie ne soit pas à jour et le code non-fonctionnel. J'espère qu'à travers cet article vous aurez pu éviter quelques pièges que j'ai eu à contourner.