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.
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 :
/proc/meminfo : RAM et swap/proc/stat : activité CPU/proc/diskstats : lectures et écritures disque
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()...
/proc sous LinuxProblè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.
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.
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.
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.
fetch() et les requêtes asynchrones en JavaScriptsetInterval() pour le rafraîchissement automatique
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.
É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.
grep, awk et les pipes pour parser du texte en bashnavigator.clipboard en HTTP
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).
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.
docker stats pour surveiller les conteneurs
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é.