# Monitoring avec InfluxDB {{INLINETOC}} Parmi les nombreuses solutions de monitoring il existe de nombreux exemples sur une stack qui utilisent: * des collecteurs permettant de collecter des données systèmes (CPU, mémoire, disque, I/O, ...): **collectd**, **telegraf** * une base de données (une TSDB((Les **TSDB** (time series database), ou bases de données de séries chronologiques, sont des systèmes logiciels optimisés pour trier et organiser des informations mesurées de manière temporelle.))) pour stocker les métriques et événements: **influxdb** * une plate-forme graphique pour la mise en forme des données métriques et alerter: **graphite**, **grafana**. COLLECTE STOCKAGE MONITORING .-=-------------------------. | .-----------. | | Métrique -->| Telegraf |-------' .----------. | .-----------. | | |[st] | .------------------. '---------------------------' '--->| | | | | InflufDB |--->| Grafana/Graphite | .-=-------------------------. '--->| | | | | .-----------. | | | | '------------------' | Métrique -->| Collectd |-------' '----------' | .-----------. | '---------------------------' [st]: {"a2s:type":"storage","a2s:delref":true} Cet article présente comment les installer et les configurer, et bien entendu les lier ensemble pour obtenir un tableau de bord clair et précis de monitoring. Lorsque **SELinux** est activé il faut autoriser les scripts et modules HTTPD à se connecter au réseau (HTTPD Service `httpd_can_network_connect`) :\\ \\ `setsebool -P httpd_can_network_connect 1`\\ \\ Il faut également accorder au processus HTTPD l'accès aux fichiers ainsi qu'aux fichiers statiques du site avec la commande:\\ \\ `chcon -v -R --type=httpd_sys_content_t /chemin/fichiers/statiques/du/site/` ##InfluxDB **InfluxDB** est une base de données open source écrit en Go spécifiquement pour gérer des séries de données chronologiques. Ses points forts sont la haute disponibilité et la haute performance. C’est **InfluxDB** qui va sauvegarder les données des colleceurs pour ensuite être utilisées par **Grafana**. ###Installation de InfluxDB Ajouter le repo YUM d’**InfluxDB**: ``` cat > /etc/yum.repos.d/influxdb.repo<<'EOF' [influxdb] name = InfluxDB Repository - RHEL \$releasever baseurl = https://repos.influxdata.com/rhel/$releasever/$basearch/stable enabled = 1 gpgcheck = 0 gpgkey = https://repos.influxdata.com/influxdb.key EOF ``` Installer le package : ``` dnf makecache dnf install influxdb -y ``` Démarrer le service : ``` systemctl start influxd systemctl enable influxd ``` Ouvrir le port **8086** dans le pare-feu: ``` firewall-cmd --add-port=8086/tcp --permanent firewall-cmd --reload ``` ### Configuration de InfluxDB Créer une base de données pour pouvoir y pousser les données remontées par les collecteurs: ``` influx -execute "CREATE DATABASE influx_db" influx -execute "CREATE DATABASE collectd_db" ``` Créer l’utilisateur **influx\_user**: ``` influx -execute “CREATE USER influx_user WITH PASSWORD 'influx-password'” influx -execute “GRANT ALL ON influx_db TO influx_user influx -execute “GRANT ALL ON collectd_db TO influx_user ``` Il est possible de créer une retention policy pour déterminer la durée de conservation des données : ``` influx -execute 'CREATE RETENTION POLICY one_year ON influx_db DURATION 365d REPLICATION 3' ``` ##Collectd **Collectd** est un service Linux qui permet de collecter, transférer et sauvegarder des données de performance concernant un ordinateur et son équipement réseau. ###Installation de collectd Son installation est simple : ``` dnf install collectd -y ``` Il est nécessaire d’activer le plugin « network » puisqu’il permettra la communication entre **collectd** et **influxdb**. Dans le fichier `/etc/collectd/collectd.conf` décommenter la ligne `LoadPlugin network` et insérer les lignes suivantes pour indiquer que **InfluxDB** est sur la même machine et écoute sur le port **25826** : ``` Server "127.0.0.1" "25826" ``` De la même manière on peut modifier le fichier `/etc/collectd/collectd.conf` pour activer ou désactiver les plugins souhaités . Pour cela il suffit de commenter ou décommenter les lignes « LoadPlugin xxxxx » (par exemple nginx, cpu, df, disk, memory, mysql, memcached). Il faut ensuite démarrer **collectd** pour prendre en compte ces modifications : ``` systemctl start collectd systemctl enable collectd ``` Activer le module **collectd** dans `/etc/influxdb/influxdb.conf`: ``` [[collectd]] enabled = true bind-address = "127.0.0.1:25826" # db files, or specifying a single db file. typesdb = "/usr/share/collectd" # security-level = "none" ``` Redémarrer le service **influxd**: ``` systemctl restart influxd ``` On peut tester la remontée avec la commande suivante: ``` curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=collectd_db" --data-urlencode "q=SELECT value FROM disk_read" ``` Ouvrir le port **25826** dans le pare-feu: ``` firewall-cmd --add-port=25826/tcp --permanent firewall-cmd --reload ``` ##Telegraf **Telegraf** est un agent de récupération de métriques. Cet agent sait récupérer des métriques exposées au format **Prometheus** et propose 2 modes de récupération des métriques, via : * **push**: la métrique est poussée dans **Telegraf** par le composant qui l’expose * **pull**: Telegraf récupère la métrique en interrogeant le composant qui l’expose (le mode le plus utilisé) Les métriques sont insérées au fil de l’eau dans **InfluxDB**. ###Installation de Telegraf Ajouter le repo YUM officiel de **Telegraf**: ``` cat > /etc/yum.repos.d/influxdb.repo<<'EOF' [influxdb] name = InfluxDB Repository - RHEL \$releasever baseurl = https://repos.influxdata.com/rhel/$releasever/$basearch/stable enabled = 1 gpgcheck = 0 gpgkey = https://repos.influxdata.com/influxdb.key EOF ``` Installer le package : ``` dnf makecache dnf install telegraf net-snmp net-snmp-libs net-snmp-utils -y ``` Configurer le backend, pour utiliser le plugin output **InfluxDB** dans `/etc/telegraf/telegraf.conf`: ``` [[outputs.influxdb]] urls = ["http://localhost:8086"] database = "influx_db" username = "influx_user" password = "influx_password" ``` Pour finir, redémarrer le service pour prendre en compte la configuration : ``` systemctl start telegraf systemctl enable telegraf ``` ###Configuration de Telegraf **Telegraf** fonctionne sous forme de plugin à activer pour récupérer les métriques. L’écosystème de plugins est riche : il y a des plugins pour monitorer nginx, cassandra, haproxy, postgresql. Dans l’ensemble, les plugins sont simples à configurer. Par exemple on va configurer un plugin pour dire à **Telegraf** de collecter les données SNMP sur un commutateur: ``` cat > /etc/telegraf/telegraf.d/sf033-a5500-013sns2.conf<<'EOF' [[inputs.snmp]] agents = [ "xx.xxx.xxx.xx" ] version = 2 community = "lanread" interval = "20s" timeout = "10s" retries = 3 [[inputs.snmp.field]] name = "hostname" oid = "RFC1213-MIB::sysName.0" is_tag = true [[inputs.snmp.field]] name = "uptime" oid = "DISMAN-EXPRESSION-MIB::sysUpTimeInstance" [[inputs.snmp.field]] name = "hh3cEntityExtCpuUsage" oid = ".1.3.6.1.4.1.25506.2.6.1.1.1.1.6.212" [[inputs.snmp.field]] name = "hh3cEntityExtMemUsage" oid = ".1.3.6.1.4.1.25506.2.6.1.1.1.1.8.212" [[inputs.snmp.field]] name = "hh3cEntityExtTemperature" oid = ".1.3.6.1.4.1.25506.2.6.1.1.1.1.12.212" # IF-MIB::ifTable contains counters on input and output traffic as well as errors and discards. [[inputs.snmp.table]] name = "switch" inherit_tags = [ "hostname" ] oid = "IF-MIB::ifTable" # Interface tag - used to identify interface in metrics database [[inputs.snmp.table.field]] name = "ifDescr" oid = "IF-MIB::ifDescr" is_tag = true # IF-MIB::ifXTable contains newer High Capacity (HC) counters that do not overflow as fast for a few of the ifTable counters [[inputs.snmp.table]] name = "switch" inherit_tags = [ "hostname" ] oid = "IF-MIB::ifXTable" # Interface tag - used to identify interface in metrics database [[inputs.snmp.table.field]] name = "ifDescr" oid = "IF-MIB::ifDescr" is_tag = true # EtherLike-MIB::dot3StatsTable contains detailed ethernet-level information about what kind of errors have been logged on an interface (such as FCS error, frame too long, etc) [[inputs.snmp.table]]Fmib name = "switch" inherit_tags = [ "hostname" ] oid = "EtherLike-MIB::dot3StatsTable" # Interface tag - used to identify interface in metrics database [[inputs.snmp.table.field]] name = "ifDescr" oid = "IF-MIB::ifDescr" is_tag = true [[inputs.snmp.table]] oid = "IF-MIB::ifTable" name = "switch" inherit_tags = ["hostname"] index_as_tag = true EOF ``` Pour déterminer l'OID de la charge du processeur, de l'utilisation de la mémoire et de la température, dans le cas d'un stack composé de plusieurs commutateurs il faut récupérer les indexes identifiés par **Board** dans la table des description , en utilisant la commande:\\ \\ `snmpwalk -v2c -clanread xx.xxx.xxx.xx SNMPv2-SMI::mib-2.47.1.1.1.1.7 | grep Board`\\ `SNMPv2-SMI::mib-2.47.1.1.1.1.7.212 = STRING: "Board"`\\ `SNMPv2-SMI::mib-2.47.1.1.1.1.7.232 = STRING: "Board"`\\ \\ Dans l'exemple étudié les OID sont donc:\\ - **hh3cEntityExtCpuUsage**: .1.3.6.1.4.1.25506.2.6.1.1.1.1.6.212 et .1.3.6.1.4.1.25506.2.6.1.1.1.1.6.232\\ - **hh3cEntityExtMemUsage**: .1.3.6.1.4.1.25506.2.6.1.1.1.1.8.212 et .1.3.6.1.4.1.25506.2.6.1.1.1.1.8.232\\ - **hh3cEntityExtTemperature**: .1.3.6.1.4.1.25506.2.6.1.1.1.1.12.212 et .1.3.6.1.4.1.25506.2.6.1.1.1.1.12.232 À la suite de l'exécution de la première commande, une liste d'OID sera affichée, ceux dans lesquels une valeur supérieure à 0 signifie une charge CPU. Si les commutateurs sont empilés, l'OID avec une valeur supérieure à zéro sera supérieur à un. La deuxième équipe se penche sur la description, la nôtre sera "Board". Implanter la MIB **DISMAN-EXPRESSION-MIB** dans le répertoire `/usr/share/snmp/mibs/`: ``` wget https://raw.githubusercontent.com/hardaker/net-snmp/master/mibs/DISMAN-EXPRESSION-MIB.txt -P /usr/share/snmp/mibs/ ``` Utiliser la commande suivante pour tester la configuration: ``` telegraf --test --config /etc/telegraf/telegraf.d/sf033-a5500-013sns2.conf ``` L'agent doit retourner des données du genre: ``` > interface,agent_host=xx.xxx.xxx.xx,dot3StatsIndex=17,host=localhost.localdomain,hostname=Sf033_A5500_013SNS2,ifDescr=GigabitEthernet1/0/17 dot3StatsAlignmentErrors=0i,dot3StatsCarrierSenseErrors=0i,dot3StatsDeferredTransmissions=0i,dot3StatsDuplexStatus=3i,dot3StatsEtherChipSet=".0.0",dot3StatsExcessiveCollisions=0i,dot3StatsFCSErrors=0i,dot3StatsFrameTooLongs=0i,dot3StatsInternalMacReceiveErrors=0i,dot3StatsInternalMacTransmitErrors=0i,dot3StatsLateCollisions=0i,dot3StatsMultipleCollisionFrames=0i,dot3StatsRateControlAbility=2i,dot3StatsRateControlStatus=3i,dot3StatsSQETestErrors=0i,dot3StatsSingleCollisionFrames=0i,dot3StatsSymbolErrors=0i 1676468198000000000 ``` ##Graphite **Graphite** est un logiciel de surveillance capable de restituer en quasi temps réel l’état de systèmes IT sous forme de graphiques. Son domaine d’activité est double : le stockage de données chronologiques de performances techniques issues des serveurs d'une part, la visualisation graphique (sous forme de courbes temporelles) des indicateurs de performance que traduisent ces données d'autre part. Pour fonctionner, le logiciel se base sur trois composantes principales : * **Carbon cache**: le daemon réseau qui se charge de récupérer les métriques * **Carbon Whisper**: la base de données qui stocke les métriques * **Graphite Web**: l’application web qui gère le rendu graphique des métriques. ###Installation de Graphite Installer les prérequis pour construire les paquets: ``` dnf groupinstall "Development Tools" dnf install python39 dnf install libffi-devel python3-devel python3.6 -m pip install --upgrade pip ``` Installer **whisper**, **carbon** et **graphite-web** avec pip: ``` pip3 install --upgrade --force-reinstall --no-binary=:all: https://github.com/graphite-project/whisper/tarball/master pip3 install --force-reinstall --no-cache-dir --no-binary=:all: https://github.com/graphite-project/carbon/tarball/mastern -v "urllib3==1.24" -v "idna==2.7" pip3 install --upgrade --force-reinstall --no-binary=:all: https://github.com/graphite-project/graphite-web/tarball/master ``` Mettre en place les fichiers de configuration ``` pushd /opt/graphite/conf cp storage-schemas.conf.example storage-schemas.conf cp carbon.conf.example carbon.conf ``` Créer les fichiers de service: ``` cat > /etc/systemd/system/graphite-web.socket<<'EOF' [Unit] Description=graphite-web socket [Socket] ListenStream=/run/graphite-api.sock ListenStream=127.0.0.1:8080 [Install] WantedBy=sockets.target EOF ``` ``` cat > /etc/systemd/system/graphite-web.service<<'EOF' [Unit] Description=graphite-web service Requires=graphite-web.socket [Service] Environment=PYTHONPATH=/opt/graphite/webapp ExecStart=gunicorn wsgi --pythonpath=/opt/graphite/webapp/graphite --bind 127.0.0.1:8080 Restart=on-failure User=root Group=root ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target EOF ``` Il faut modifier la valeur **SECRET\_KEY** par défaut dans le fichier `/etc/graphite/local_settings.py` utilisé par graphite-web :\\ \\ `SECRET_KEY = 'MY_SECRET' # entrez votre propre clé secrète`\\ \\ Sinon, on aura une erreur lors du démarrage du service de l'application graphite-web Mettre à jour la configuration de **Nginx**: ``` upstream graphite { server 127.0.0.1:8080 fail_timeout=0; } server { listen 80; server_name sonde; root /opt/graphite/webapp; access_log /var/log/nginx/graphite.access.log; error_log /var/log/nginx/graphite.error.log; location = /favicon.ico { return 204; } # serve static content from the "content" directory location /static { alias /opt/graphite/webapp/content; expires max; ``` On peut ensuite démarrer **graphite-web** pour prendre en compte ces modifications : ``` systemctl start graphite-web systemctl enable graphite-web ``` ##Grafana **Grafana** est un outil supervision, permettant de s’intégrer à une TSDB, ici **InfluxDB**. **Grafana** expose dans des dashboards les métriques brutes ou agrégées provenant d’**InfluxDB** et permet de définir de manière honteusement simple des seuils d’alertes et les actions associées. Il est simple à utiliser, permet l’actualisation en temps réel ainsi que le déplacement dans le temps pour visualiser ses informations par dates (hier, aujourd’hui, les 6 dernières heures, etc). ###Installation de Grafana Ajouter le repo YUM officiel de **Grafana**: ``` cat > /etc/yum.repos.d/grafana.repo<<'EOF' [grafana] name=grafana baseurl=https://packages.grafana.com/oss/rpm repo_gpgcheck=1 enabled=1 gpgcheck=1 gpgkey=https://packages.grafana.com/gpg.key sslverify=1 sslcacert=/etc/pki/tls/certs/ca-bundle.crt EOF ``` Installer le package : ``` dnf makecache dnf install grafana -y ``` Démarrer le service : ``` systemctl daemon-reload systemctl start grafana-server systemctl enable grafana-server ``` Ouvrir le port **3000** dans le pare feu: ``` firewall-cmd --add-port=3000/tcp --permanent firewall-cmd --reload ``` ###Configuration de Grafana La première étape dans **Grafana** est d’ajouter la source de donnée (**InfluxDB**). Aller dans “Datasource” puis “Add Datasource” et ajouter la base **Influxdb**. * **Database**: influx_db * **Username**: influx_user * **Password**: influx-password Ensuite pour créer les dashboards, on peut récupérer des dashboards de la communauté Grafana ou créer des dashboards. Par exemple pour mettre en place un tableau de bord simple montrant le débit des interfaces: Choisir le plugin d'affichage dans **option panel**, par exemple **Gauge** pour afficher les statistiques sous forme de jauges. Pour installer des plugins packagés, une fois que l'archive contenant les actifs du plug-in est téléchargé, on peut l'installer en extrayant l'archive dans le répertoire de plug-in:\\ \\ `unzip mon-plugin-0.2.0.zip -d YOUR_PLUGIN_DIR/mon-plugin`\\ \\ Le chemin d'accès au répertoire du plugin est défini dans le fichier de configuration `/etc/grafana/grafana.ini`: \\ `# Directory where grafana will automatically scan and look for plugins`\\ `;plugins = /var/lib/grafana/plugins`\\ \\ Il est possible d'installer des plugins avec Grafana CLI (Toutes les commandes répertoriées s'appliquent aux référentiels et répertoires par défaut de Grafana, on peut remplacer les valeurs par défaut avec les options globales):\\ \\ - Lister les plugins disponibles: `grafana-cli plugins list-remote`\\ - Lister les plugins installés: `grafana-cli plugins ls`\\ - Installer la dernière version d'un plugin: `grafana-cli plugins install `\\ - Installer une version spécifique d'un plugin: `grafana-cli plugins install `\\ - Mettre à jour un plugin: `grafana-cli plugins update `\\ - Mettre à jour tous les plugins: `grafana-cli plugins update-all`\\ - Supprimer un plugin: `grafana-cli plugins remove ` Définir la requête (onglet `Query`) comme suit: ^ A | (InfluxDB) |||||| ^ FROM | `autogen` | `interface` ^ WHERE | `hostname` | = | `Sf033_A5500_013SNS2` | ^ SELECT | `field(ifHCOutOctets)` | `mean()` | `derivative(10s)` | `math(/100)` || `alias(output)` | ^ GROUP BY | `time($__interval)` | `tag(ifDescr)` | `fill(null)` | || | ^ Time Zone | (optional) |^ ORDER BY TIME | `ascending` || | ^ Limit | (optional) |^ SLIMIT | (optional) || | ^ FORMAT AS | `Time series` |^ ALIAS | `$tag_ifDescr $col` || | Les points importants à noter sont : * Utilisation des champs **ifHCInOctets/ifHCOutOctets** comptent la même chose que les compteurs **ifInOctets/ifOutOctets** mais ils sont de type counter64 (compteur sur 64 bits) alors que les premiers sont de type counter32 (compteur sur 32 bits). Passer les compteurs en 64 bits est devenu nécessaire à cause des interfaces haut débit (10Gbps et plus) car à ce débit avec un compteur sur 32 bits on a vite fait de faire "faire un tour" au compteur d'octets et ça devient donc difficile de mesurer le débit de manière fiable. Le **ifInOctets/ifOutOctets** est gardé pour des raisons de compatibilité avec les applications qui ne géreraient pas les variables de type counter64. Lorsqu'on utilise ces compteurs il faut utiliser un algorithme de transformation dans le bloc SELECT (ici **derivative(10s)**) * Utilisation de **derivative(10s)**. Les données sous-jacentes sont stockées sous la forme d'un compteur qui s'incrémente tous les 8 bits reçus. Ce n'est pas particulièrement utile en soi. En utilisant **derivative()**, combiné avec **math(8)**, on peut calculer les bits par seconde. * le nom d'hôte de commutateur est **Sf033\_A5500\_013SNS2** * l'**alias (output)** affecté au champs permet de référencé celui-ci avec la variable **$col** dans le paramètre **ALIAS** * Regroupement par heure et par balise (**ifDescr**) - cela divise les données en lignes distinctes par interface. * Le paramètre **ALIAS** contrôle les étiquettes attribuées à chaque série. Dans ce cas, il apparaît comme quelque chose comme **TenGigabitEthernet 34/0/1 Output**.