Munin

Le corbeau et le café

Luc Didry

13 juin 2014

Contexte

Munin est un outil de supervision

Caractéristiques :

  • écrit en Perl ;
  • simple d'utilisation ;
  • extensible.

Pourquoi utiliser Munin ?

Bah oui, il y a déjà plein d'autres solutions !

Certes, mais Munin n'a pas pour but de remplacer Nagios

Munin est plutôt un excellent complément à d'autres outils de supervision :

  • granularité fine ;
  • graphiques ;
  • historique ;
  • développement très facile de nouvelles sondes.

En supervision comme ailleurs, il vaut mieux privilégier le dicton

« À chaque besoin sa solution »

One size doesn't fit all
One size doesn't fit all

Généralités et architecture de Munin

En vrac :

  • plus de 10 ans ;
  • écrit en Perl avec peu de dépendances ;
  • nommé d'après le corbeau d'Odin, Munin, dont le nom signifie « mémoire » ;
  • collecte et génération de graphes => à ranger plutôt dans les outils de métrologie ;
  • disponible sur toutes les bonnes distributions GNU/Linux, GNU/Hurd ou BSD ;
  • simple d'installation et de configuration ;
  • auto-adaptation aux possibilités du système ;
  • possibilité d'alertes.

Simplicité et sobriété

  • pages html et images générées statiquement ou dynamiquement ;
  • pas de gestion de compte utilisateur ou de droits d'accès.

tout en restant efficace

  • possibilité d'utilisation des graphes dans un portail externe ;
  • zoom dynamique sur les graphes (à partir de la v2.0).
Page d'accueil
Page d'accueil
Détail d'un nœud
Détail d'un nœud
Interface de zoom dynamique
Interface de zoom dynamique

Architecture master/slave

ou plutôt master/node

Le nœud (node, in the langue de Shakespeare)

  • installé sur les machines à superviser ;
  • écoute sur 4949/TCP ;
  • exécute des plugins (sondes, dans le language of Molière) à la demande du maître (mestari, kielellä Arto Paasilinna).

Le maître

  • surveille un ou plusieurs nœuds ;
  • se connecte aux nœuds sur le 4949/TCP, leur faisant exécuter les sondes ;
  • collecte les données et génère les graphes et les pages HTML.

Nota Bene

Il n'y a aucun problème pour installer un nœud et un maître sur la même machine qui du coup s'auto-supervise.

Here comes the fun : les sondes

Qu'est-ce que c'est ?

  • ce sont des exécutables récupérant les données au plus près de l'objet supervisé ;
  • ils peuvent écrits dans n'importe quel langage (bash, Perl, Ruby, Lisp, Cobol…).

Lors de l'exécution d'une sonde…

Le maître demande deux choses à la sonde (via le nœud) :

  • les méta-données pour savoir ce que fait la sonde et comment générer les graphes ;
  • les valeurs numériques de la (des) métrique(s) surveillée(s).

TOUT EST DANS LA SONDE

(et ça c'est bien cool)

Exemple

La sonde dns_query_time mesure le temps de réponse à la question « IN NS . » avec la commande dig

$ ./dns_query_time config         # renseignements sur le plugin
graph_title  DNS query time       # titre du graphe
graph_vlabel time in ms           # label de l’axe des Y
time.label   query time

$ ./dns_query_time                # interrogation de la valeur
time.value 42

Code de base

#!/bin/bash

case $1 in
   config)
        cat <<EOF
graph_title DNS query time
graph_vlabel time in ms
time.label query time
EOF
        exit 0;;
esac

printf "time.value "
dig IN NS . | grep '^;; Query time:' | cut -d' ' -f4

Pour activer la sonde, un simple lien symbolique dans /etc/munin/plugins suffit !

(avec un /etc/init.d/munin-node restart quand même)

On peut aussi tester la sonde avec munin-run avant de redémarrer le service :

munin-run dns_query_time

Le protocole de communication étant fort simple, on peut tester la sonde en conditions réélles avec telnet :

$ telnet localhost 4949
Trying 127.0.0.1...
Connected to localhost
Escape character is '^]'.
# munin node at localhost
list                                        # liste des plugins activés
cpu if_eth0 load memory dns_query_time
config dns_query_time                       # vérification config
graph_title DNS query time
graph_vlabel time in ms
time.label query time
.
fetch dns_query_time                        # interrogation des données
time.value 6

Les sondes Munin sont extrêmement facile à développer !

On peut les faire dans son langage préféré (Perl, bien sûr) et profiter de ses bibliothèques.

Le module Munin::Plugin est là pour vous simplifier le travail.

(perldoc Munin::Plugin)

Cas d'école

Une sonde pour superviser la cafetière

Oui, oui, vous avez bien lu la cafetière !

On peut vraiment tout monitorer simplement avec Munin ☺

Le but

Surveiller le niveau de café dans la cafetière.

Comment ?

On va prendre des photos de la cafetière avec une webcam et voir où en est le niveau de café.

Mais ça va être vachti compliqué, non ?

Non

On n'a besoin que de Munin::Plugin, Image::Magick, ffmpeg et zbar.

(Dingue, non ?)

(Ouais, nan, pas tant que ça, c'est du lourd quand même.)

ffmpeg servira à capter le flux vidéo de la webcam et à en faire une photo.

zbar servira à lire un QR code sur la photo.

Image::Magick servira à lire l'image et déterminer le niveau de café.

Munin::Plugin fournira quelques facilités d'écriture.

Un bon début.

use warnings;
use strict;
use Munin::Plugin;
use Image::Magick;

my $PICTURE = "$Munin::Plugin::pluginstatedir/picture.jpg";
my $START_X = $ENV{start_pixel_x};
my $START_Y = $ENV{start_pixel_y};
my $RMIN = $ENV{r_min} || 0;
my $RMAX = $ENV{r_max} || 0.2;
my $GMIN = $ENV{g_min} || 0;
my $GMAX = $ENV{g_max} || 0.2;
my $BMIN = $ENV{b_min} || 0;
my $BMAX = $ENV{b_max} || 0.2;
my $HEIGHT = $ENV{height} || 100;
my $DEVICE = (defined $ENV{device}) ? $ENV{device} : "/dev/video0";

On peut voir ici une utilisation de Munin::Plugin.

$Munin::Plugin::pluginstatedir nous fournit un répertoire dans l'arborescence pour stocker des fichiers.

Quelques fonctions internes

sub _munin_exit_done {
    _munin_exit(0);
} ## sub _munin_exit_done

sub _munin_exit_fail {
    _munin_exit(1);
} ## sub _munin_exit_fail

sub _munin_exit {
    my $exitcode = shift;
    exit($exitcode) if(defined $exitcode);
    exit(1);
} ## sub _munin_exit

(Rien d'intéressant ici)

Affichage de la configuration de la sonde.

if( (defined $ARGV[0]) && ($ARGV[0] eq "config") ) {
    print "graph_title Coffee level\n";
    print "graph_vlabel level of coffee in coffee pot\n";
    print "graph_info How much coffee there is in the coffee pot\n";
    print "graph_args -u 100 -l 0\n";
    print "coffee.label coffee level\n";
    print_thresholds('coffee');
    print "coffee.draw AREA\n";
    ## Done !
    _munin_exit_done();
}

Simple, non ?

Mais ! Qu'est-ce que c'est que ce print_thresholds('coffee') ?

Simplement une fonction de Munin::Plugin qui affiche les seuils d'alertes warning et critical s'ils existent dans la conf.

Allons-y Alonzo !

# take picture
if (!-e $DEVICE) {
    print $Munin::Plugin::me." Can't see video device: $DEVICE\n";
    _munin_exit_fail();
}
if (system("ffmpeg -y -f video4linux2 -i $DEVICE -vframes 1 $PICTURE")) {
    print $Munin::Plugin::me." Error while taking photo from";
    print "video device $DEVICE to $PICTURE\n";
    _munin_exit_fail();
}

# check if the coffee pot is present with QRcode
_munin_exit_done() unless (`zbarimg $PICTURE` =~ m/QR-Code:present/m);

$Munin::Plugin::me retourne le nom de la sonde.

C'est équivalent à basename $0 dans un script shell.

Plutôt utile pour les messages d'erreur !

Manipulons donc notre image…

# get the ruler pixels informations
my $image = new Image::Magick;
$image->Read($PICTURE);
my @pixels = $image->GetPixels(
    x => $START_X,
    y => $START_Y,
    width => 1,
    height => $HEIGHT,
    normalize => 1
);
for (my $i = $START_Y; $i < $START_Y + $HEIGHT; $i++) {
    $image->Set('pixel['.$START_X.','.$i.']' => 'red');
}
$image->Write('/tmp/coffee_check.png');

Ceci ne sert quasiment qu'à étalonner la sonde.

Mesurons le niveau de café.

my @cleaned;
while (scalar @pixels) {
    push @cleaned, {
       r => shift @pixels,
       g => shift @pixels,
       b => shift @pixels
    };
}

# get the level
my $i = 0;
foreach my $pixel (@cleaned) {
    if ($pixel->{r} >= $RMIN && $pixel->{r} < $RMAX &&
        $pixel->{g} >= $GMIN && $pixel->{g} < $GMAX &&
        $pixel->{b} >= $BMIN && $pixel->{b} < $BMAX ) {
        my $level = 100 * ($HEIGHT - $i) / $HEIGHT;
        printf "coffee.value %.2f\n", $level;
        _munin_exit_done();
    }
    $i++;
}
printf "coffee.value 0\n";

_munin_exit_done();
Le montage
Le montage
Le résultat
Le résultat

Bilan :

  • ±100 lignes de code ;
  • toujours du café à disposition ;
  • un graphe de la consommation de café dans la journée ;
  • du fun pour le codeur ☺ !

Conclusion :

  • non, on ne doit pas abandonner son Nagios, mais plutôt utiliser Munin en complément d'un autre outil plus classique ;
  • il n'y a absolument aucune limite aux capacités de supervision de Munin ;
  • sauf les capacités du langage choisi / du développeur ;
  • idéal pour un suivi de métriques précises ;
  • très utile pour de l'analyse post-incident ;

Questions ?

Présentation adaptée de l'article et de la présentation des JRES 2013

« Munin : superviser simplement la machine à café… enfin une réalité ! »

https://conf-ng.jres.org/2013/planning.html#article_60

Par Alexandre Simon
Par Alexandre Simon
Et votre serviteur
Et votre serviteur
Logo Université de Lorraine
Pour l'Université de Lorraine

http://munin-monitoring.org

http://github.com/ldidry
http://twitter.com/framasky
http://slides.fiat-tux.fr