Monitoring avec rrdtool

Le logiciel rrdtool permet de générer des graphes avec une base de données remplie au fil du temps. L'interêt est qu'il dispose d'une méthode pour que sa base de données conserve sa taille quel que soit la durée d'execution. RRD est l'acronyme de Round Robbin Database.

Compilation de rrdcollect

Le logiciel rrdcollect permet d'automatiser le remplissage des bases de données de rrdtool. Cependant il n'est pas empaqueté pour Debian stable, il faut donc le compiler.

Les bibliothèques librrd0-dev et libpcre3-dev sont nécessaires à la compilation :

apt-get install librrd0-dev librrd0-dev

Une fois l'archive de rrdcollect téléchargée, il faut le compiler :

tar xvzf rrdcollect-0.2.3.tar.gz
cd rrdcollect-0.2.3/
dpkg-buildpackage

Le fichier rrdcollect_0.2.1-3_i386.deb est créé dans le répertoire superieur. Ce paquet sera installé sur toutes les machines à monitorer.

Le fichier de configuration /etc/rrdcollect.conf sert à définir les commande à lancer pour determiner les données à enregister. Ici on analyse la charge CPU et mémoire toutes les 60 secondes:

step = 60
directory = /root/rrd

file:/*proc/meminfo
/^MemTotal:\s*(\d+) kB/         mem.rrd:mem_total
/^MemFree:\s*(\d+) kB/          mem.rrd:mem_free

file:/*proc/stat
/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/  cpu.rrd:cpu_user,cpu_nice,cpu_system,cpu_idle,cpu_iowait,cpu_irq,cpu_softirq

Création des bases

Le script /root/rrd/create.sh permet de créer les bases pour monitorer le CPU et la mémoire :

#!/bin/bash
RRDPATH=/root/rrd

rrdtool create $RRDPATH/mem.rrd \
        --start `date +%s` \
        --step 60 \
        DS:mem_total:GAUGE:150:0:U \
        DS:mem_free:GAUGE:150:0:U \
        RRA:AVERAGE:0.5:1:1440 \
        RRA:AVERAGE:0.5:10:1008 \
        RRA:AVERAGE:0.5:60:744


rrdtool create $RRDPATH/cpu.rrd \
        --start `date +%s` \
        --step 60 \
        DS:cpu_user:COUNTER:150:0:100 \
        DS:cpu_nice:COUNTER:150:0:100 \
        DS:cpu_system:COUNTER:150:0:100 \
        DS:cpu_idle:COUNTER:150:0:100 \
        DS:cpu_iowait:COUNTER:150:0:100 \
        DS:cpu_irq:COUNTER:150:0:100 \
        DS:cpu_softirq:COUNTER:150:0:100 \
        RRA:AVERAGE:0.5:1:1440 \
        RRA:AVERAGE:0.5:10:1008 \
        RRA:AVERAGE:0.5:60:744
  • la ligne RRA:AVERAGE:0.5:1:1440 signifie qu'on fait la moyenne (AVERAGE:0.5) sur 1 échantillon et qu'on en garde 1440 exemplaires (1440 = 60 * 24). On garde tous les relevés pendant une journée.
  • la ligne RRA:AVERAGE:0.5:10:1008 signifie qu'on fait la moyenne (AVERAGE:0.5) sur 10 échantillons et qu'on en garde 1008 exemplaires (1008 = ( 60 * 24 * 7) / 10). On fait une moyenne toutes les 10 minutes et on les garde pendant 7 jours.
  • la ligne RRA:AVERAGE:0.5:60:744 signifie qu'on fait la moyenne (AVERAGE:0.5) sur 60 échantillons et qu'on en garde 744 exemplaires ( 744 = ( 60 * 24 * 31 ) / 60). On fait la moyenne toutes les heures et on les gardes pendant 1 mois.

Génération des graphes

Les graphes sont stockés dans le répertoire du site web. Le script qui les créé est /root/rrd/graph.sh :

#!/bin/bash
RRDPATH=/root/rrd
WEBPATH=/var/www/rrd
MEM_LIM="4.5e+09"
MEM_LBL="4Go"
MEM_HR="4.29e+09"

rrdtool graph $WEBPATH/mem-3h.png \
        --title 'Memoire utilisée sur 3 heures' \
        --start -3h --end now \
        --base 1024 \
        --upper-limit $MEM_LIM --lower-limit 0 -r \
        DEF:mem_total=$RRDPATH/mem.rrd:mem_total:AVERAGE \
        DEF:mem_free=$RRDPATH/mem.rrd:mem_free:AVERAGE \
        CDEF:mem_used=mem_total,mem_free,-,1024,* \
        'AREA:mem_used#00FF00:M\xe9moire utilis\xe9e' \
        HRULE:$MEM_HR'#FF0000:Limite \: '$MEM_LBL

rrdtool graph $WEBPATH/cpu-3h.png -o \
        --title 'Charge CPU sur 3 heures' \
        --start -3h --end now \
        DEF:cpu_user=$RRDPATH/cpu.rrd:cpu_user:AVERAGE \
        DEF:cpu_nice=$RRDPATH/cpu.rrd:cpu_nice:AVERAGE \
        DEF:cpu_system=$RRDPATH/cpu.rrd:cpu_system:AVERAGE \
        DEF:cpu_idle=$RRDPATH/cpu.rrd:cpu_idle:AVERAGE \
        DEF:cpu_iowait=$RRDPATH/cpu.rrd:cpu_iowait:AVERAGE \
        DEF:cpu_irq=$RRDPATH/cpu.rrd:cpu_irq:AVERAGE \
        DEF:cpu_softirq=$RRDPATH/cpu.rrd:cpu_softirq:AVERAGE \
        'AREA:cpu_iowait#0000FF:IO wait' \
        'STACK:cpu_system#FF9999:system' \
        'STACK:cpu_nice#FF99FF:nice' \
        'STACK:cpu_user#99FF99:user' \
        'STACK:cpu_idle#FFFFFF:idle'

rrdtool graph $WEBPATH/mem-7d.png \
        --title 'Memoire utilisée sur 7 jours' \
        --start -7d --end now \
        --base 1024 \
        --upper-limit $MEM_LIM --lower-limit 0 -r \
        DEF:mem_total=$RRDPATH/mem.rrd:mem_total:AVERAGE \
        DEF:mem_free=$RRDPATH/mem.rrd:mem_free:AVERAGE \
        CDEF:mem_used=mem_total,mem_free,-,1024,* \
        'AREA:mem_used#00FF00:Memoire utilisée' \
        HRULE:$MEM_HR'#FF0000:Limite \: '$MEM_LBL

rrdtool graph $WEBPATH/cpu-7d.png -o \
        --title 'Charge CPU sur 7 jours' \
        --start -7d --end now \
        DEF:cpu_user=$RRDPATH/cpu.rrd:cpu_user:AVERAGE \
        DEF:cpu_nice=$RRDPATH/cpu.rrd:cpu_nice:AVERAGE \
        DEF:cpu_system=$RRDPATH/cpu.rrd:cpu_system:AVERAGE \
        DEF:cpu_idle=$RRDPATH/cpu.rrd:cpu_idle:AVERAGE \
        DEF:cpu_iowait=$RRDPATH/cpu.rrd:cpu_iowait:AVERAGE \
        DEF:cpu_irq=$RRDPATH/cpu.rrd:cpu_irq:AVERAGE \
        DEF:cpu_softirq=$RRDPATH/cpu.rrd:cpu_softirq:AVERAGE \
        'AREA:cpu_iowait#0000FF:IO wait' \
        'STACK:cpu_system#FF9999:system' \
        'STACK:cpu_nice#FF99FF:nice' \
        'STACK:cpu_user#99FF99:user' \
        'STACK:cpu_idle#FFFFFF:idle'

Lancement des scripts

Le script de démarrage fournit par la compilation de rrdcollect (/etc/init.d/rrdcollect) n'est pas fonctionnel, il faut le remplacer par celui-ci :

#! /bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/rrdcollect
NAME=rrdcollect
DESC=rrdcollect

test -f $DAEMON || exit 0

set -e

case "$1" in
  start)
        echo "Starting $DESC: $NAME"
        start-stop-daemon --start --quiet --make-pidfile --pidfile /var/run/$NAME.pid \
                --background --exec $DAEMON -- -n
        ;;
  stop)
        echo "Stopping $DESC: $NAME"
        start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/$NAME.pid \
                --exec $DAEMON
        ;;
  restart|force-reload)
        echo "Restarting $DESC: $NAME"
        start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/$NAME.pid \
                --exec $DAEMON
        sleep 1
        start-stop-daemon --start --quiet --make-pidfile --pidfile /var/run/$NAME.pid \
                --background --exec $DAEMON -- -n
        ;;
  *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload}" >&2
        exit 1
        ;;
esac

exit 0

Le script qui calcul l'espace disque occupé par les utilisateurs est à placer dans /root/espace-disque/calcul.sh :

#!/bin/bash
SILENT=true
cd /root/espace-disque/
[ $SILENT = "true" ] || echo "Calcul de l'espace occupe..."
du -h -s /home/* > resume
sort -n resume > /var/www/resume-tri

Ensuite il faut lancer la création de graphe automatiquement. Pour ne pas surcharger la machine, on va regénérer les graphes toutes les 5 minutes en utilisant la crontab :

*/5 * * * * /root/rrd/graph.sh
0 12 * * 0 /root/espace-disque/calcul.sh

Apache

Le serveur Apache va afficher toutes les informations que l'on va collecter. On souhaite avoir une page qui donne les informations sur l'état de la machine. L'application [http://phpsysinfo.sourceforge.net|phpsysinfo] donne un apercu des ressources systèmes :

apt-get install phpsysinfo

La page d'accueil est à placer dans /var/www/index.html :

<html>
<head>
    <title>Monitoring de la machine</title>
</head>
<body>
<div>
<h1>Monitoring de la machine</h1>
<ul>
    <li><a href="phpsysinfo/">phpsysinfo</a></li>
    <li><a href="rrd.html">Charge syst&egrave;me</a></li>
    <li><a href="disque.php">Espace disque</a></li>
</ul>
</div>
</body>
</html>

Le fichier /var/www/rrd.html contient les images générées automatiquement :

<html>
<head>
        <title>Charge syst&egrave;me</title>
</head>
<body>
<div>
<h1>Charge syst&egrave;me</h1>
<h2>Charge CPU sur 3 heures</h2>
<p><img src="rrd/cpu-3h.png" alt="Charge CPU sur 3 heures"/></p>
<h2>Charge m&eacute;moire sur 3 heures</h2>
<p><img src="rrd/mem-3h.png" alt="Charge m&eacute;moire sur 3 heures"/></p>
<h2>Charge CPU sur 7 jours</h2>
<p><img src="rrd/cpu-7d.png" alt="Charge CPU sur 7 jours"/></p>
<h2>Charge m&eacute;moire sur 7 jours</h2>
<p><img src="rrd/mem-7d.png" alt="Charge m&eacute;moire sur 7 jours"/></p>
</div>
</body>
</html>

Le fichier /var/www/disque.php contient la liste des utilisateurs prenant plus de 500Mo d'espace disque :

<?php
echo "<html>
<head>
    <title>Consommation d'espace disque</title>
    <meta http-equiv="Refresh" content="300"/>
    <meta http-equiv="Pragma" content="no-cache"/>
</head>
<body>
<div>
<h1>Consommation d'espace disque</h1>
<p>Liste des utilisateurs prenant plus de 500Mo d'espace disque.</p>

<ul>";
$path = 'resume-tri';
$fichier = @file( $path );
if ( $fichier == null ) {
    exit();
}
reset($fichier);
foreach ( $fichier as $line ) {
    $line = rtrim( $line );
    $line = ltrim( $line );
    if ($line == "" || $line == "\n" || strstr( $line, "#" ) ) {
        next($config);
    }
    else {
        # recupere les compte qui ont plus d'1Go
        # (taille) (unite) (chemin)
        preg_match( "/(\d+\.?\d+)([G])\s*(.*)/", $line, $res );
        if ( strlen( $res[0] ) != 0 ) {
            list( , , ,$uid ) = explode( '/', $res[3] );
            echo "<li>$uid consomme " . $res[1] . $res[2] . "</li>\n";
        }
    }
}
echo "</ul>
</div>
</body>
</html>";
?>