← Retour aux projets

Dashboard de monitoring serveur

Python Flask JavaScript Linux Docker Bash

Après avoir monté mon serveur NAS, je voulais pouvoir surveiller ses performances en temps réel. Des outils tout faits existent, mais les installer sans comprendre ce qu'il se passe dessous ne m'intéressait pas. J'ai donc tout fait moi-même : le script Python qui lit dans le noyau Linux, l'API, et l'interface web avec les graphiques.

Vue générale du dashboard

Étape 1 : Lire dans le noyau Linux

Linux expose toutes les informations système dans des fichiers texte, dans /proc. Pas besoin de bibliothèque spéciale, on les lit comme n'importe quel fichier. Pour ce projet j'en utilise trois :

Pour la RAM c'est facile, on extrait MemTotal et MemAvailable et on calcule. Le CPU m'a donné plus de fil à retordre. En ouvrant /proc/stat, on tombe sur ça :

cpu  15142 4 7222 2847174 11190 0 227 0 0 0
cpu0 7936 0 3303 1423439 5452 0 202 0 0 0
cpu1 7206 4 3918 1423734 5737 0 25 0 0 0
intr 1449443 41 4 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 65588 43297 0 31 3 192949 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 2729221
btime 1780565299
processes 8917
procs_running 1
procs_blocked 0
softirq 780745 1 175532 36520 209641 22998 0 14931 228905 4 92213

Ce sont des compteurs qui tournent depuis le démarrage de la machine. Le noyau classe son activité en catégories (temps passé sur les programmes, dans le noyau, à ne rien faire...) et compte. Une seule lecture ne dit donc rien sur la charge actuelle. Il faut lire deux fois à une seconde d'écart et calculer la différence. Même principe pour le disque, sauf que là on compte des secteurs de 512 octets lus et écrits.

J'ai regroupé tout ça dans une classe Computer avec une méthode par groupe de métriques : ramUpdate(), CPUUpdate(), memoryUpdate()...

Ce que j'ai appris


Étape 2 : L'API Flask

Problème suivant : mon script Python a les données, mais elles sont bloquées dedans. Comment les faire arriver jusqu'à une page web ? La réponse c'est une API REST. J'ai utilisé Flask, une bibliothèque qui permet de créer des mini serveurs web en Python.

Le principe : quand le navigateur appelle l'URL /metrics, Flask déclenche ma fonction Python et renvoie les métriques au format JSON. Une simple requête HTTP et les données voyagent.

{
  "cpu0_pct": 0,
  "cpu1_pct": 0,
  "cpu_pct": 3.03030303030303,
  "memory_free": 68.66,
  "memory_read": 0,
  "memory_total": 144.63,
  "memory_used": 68.56,
  "memory_write": 0,
  "ram_actual": 766720,
  "ram_availible": 1254188,
  "ram_max": 2020908,
  "swap_actual": 0,
  "swap_free": 1046524,
  "swap_total": 1046524,
  "temp_cpu": 34,
  "uptime": "2383.51"
}

Petite surprise au moment d'installer Flask : impossible de faire pip install directement sur Debian. Le système protège son Python (erreur externally-managed-environment). C'est comme ça que j'ai découvert les environnements virtuels avec venv, une bulle isolée par projet où on installe ce qu'on veut sans toucher à l'OS.

Ce que j'ai appris


Étape 3 : L'interface web

Je n'avais jamais fait de web avant ce projet. J'ai demandé à Claude de me faire le HTML et le CSS, et je me suis chargé du JavaScript. Le cœur du système c'est fetch(), une fonction JS qui appelle mon API toutes les secondes en arrière-plan et met à jour la page sans la recharger.

Page RAM

Pour les graphiques, j'avais deux options : stocker l'historique dans un fichier CSV, ou tout garder en mémoire dans un tableau JavaScript. Le CSV est fiable et donne un vrai historique, mais c'est lourd et un peu overkill pour un dashboard temps réel. J'ai pris la deuxième option : un tableau glissant de 600 valeurs, soit 10 minutes de données à raison d'une par seconde.

Page CPU

Le dashboard a 5 onglets : Général, RAM, Stockage, CPU et Diagnostic. Sur la page CPU j'affiche la charge globale mais aussi le détail de chaque cœur, puisque /proc/stat donne une ligne par cœur.

Ce que j'ai appris


La page diagnostic

Une idée qui me tenait à cœur : si le serveur se comporte bizarrement, un bouton génère un rapport complet avec tout le contenu brut des fichiers /proc et les métriques calculées. On peut copier les données telles quelles, ou copier directement un prompt tout fait à coller dans une IA pour se faire diagnostiquer le serveur.

Page diagnostique

Évidemment, si le serveur est complètement mort, le dashboard ne sert plus à rien. J'ai donc aussi écrit un script bash qui fait le même diagnostic directement dans le terminal, avec des couleurs selon les seuils. Utilisable en SSH ou avec un écran branché sur le serveur.

Ce que j'ai appris


Dockerisation

Pour finir, j'ai mis le dashboard dans un conteneur Docker. Trois fichiers suffisent : un Dockerfile (la recette pour construire l'image), un requirements.txt (la liste des bibliothèques) et un docker-compose.yml (comment lancer le tout).

- /sys:/sys

Résultat : le dashboard tourne en permanence, se relance tout seul au démarrage du serveur, et consomme environ 24 Mo de RAM. Très raisonnable.

Ce que j'ai appris


Bonus : Nextcloud

Dans la foulée, j'ai installé Nextcloud sur le serveur : un Google Drive/Photos auto-hébergé. Cette fois pas de from scratch, l'image Docker officielle fait très bien le travail. Un docker-compose.yml avec MariaDB pour la base de données, et c'est accessible depuis tout le réseau local.

Prochaine étape : rendre tout ça accessible depuis l'extérieur de la maison. Plutôt que d'ouvrir des ports sur ma box (et m'exposer aux scans permanents des bots), je pense passer par un VPN qui permet d'accéder au réseau local à travers un tunnel chiffré.

État du projet

Dashboard actif en Docker
RAM, CPU, Disque, Température
Historique 10 min par métrique
Page diagnostic + prompt IA
Script bash standalone
Nextcloud installé