MONITORER SON DÉBIT INTERNET


 23 Septembre 2020  |  11 mins   Arnaud Veber

LE PROJET

Il y a quelques mois j’ai changé de contrat internet à mon domicile, passant par la même occasion sur la fibre. Passé l’excitation d’une connexion beaucoup plus rapide, j’ai commencé à ressentir de la frustration à la moindre petite latence. Par conscience scientifique curiosité, j’ai voulu déterminer si ces latences étaient psychologiques ou bien réelles en testant régulièrement ma connexion internet avec speedtest.net pour finalement me dire qu’une automatisation était certainement possible.

Après quelques recherches et la découverte de l’utilitaire speedtest-cli, le projet était lancé.

L’objectif étant de récupérer à intervalle régulier, d’historiser et de consulter ces mesures.

 

ARCHITECTURE GLOBALE DU PROJET

Notre projet se décompose en deux parties : d’une part le stockage et la visualisation des métriques, et d’autre part la récupération de ces métriques. Le tout sera hébergé sur un Raspberry Pi avec docker et docker-compose.

 

Pour la première partie, stockage et visualisation des métriques, nous allons utiliser InfluxDB et Grafana. InfluxDB est une base de données time series conçue pour supporter des charges soutenues en lecture et en écriture. Grafana est une solution d’analyse et de monitoring supportant de nombreuses sources de données.

Pour la seconde partie, récupération des métriques, nous allons utiliser notre version conteneurisée de speedtest-cli. L’exécution de cette tache sera planifiée pour un lancement toutes les 10 minutes à l’aide d’un cron job sur le raspberry pi.

Les présentations étant faites, enchaînons directement avec la création des composants de notre projet.

STOCKAGE ET VISUALISATION DES MÉTRIQUES

Voyons tout de suite la stack docker-compose permettant la mise en place de la partie stockage et visualisation, puis prenons le temps de la comprendre.

./docker-compose.yaml

version: "3.7"

services:

  grafana:

    image: grafana/grafana:7.1.5

    volumes:

      - "grafana-storage:/var/lib/grafana"

    networks:

      - speedtest

    ports:

      - "3000:3000"

  influxdb:

    image: influxdb:1.8.2

    volumes:

      - "influxdb-data:/var/lib/influxdb"

    networks:

      - speedtest

    expose:

      - "8086"

networks:

  speedtest:

    name: speedtest

    driver: bridge

volumes:

  grafana-storage:

  influxdb-data:

Cette stack docker-compose en version "3.7" définit nos deux services, grafana et influxdb. Elle définit également deux volumes grafana-storage et influxdb-data, et un network speedtest en bridge.

Le service grafana lance un conteneur Docker basé sur l’image officielle grafana/grafana en version 7.1.5, attache le volume grafana-storage au point de montage /var/lib/grafana pour la persistance des données de configuration de Grafana, utilise le réseau speedtest et mappe le port 3000 de l’hôte (le raspberry pi) au port 3000 du conteneur (Grafana) nous permettant ainsi d’atteindre l’interface de Grafana via l’url http://<ip_raspberry_pi>:3000/.

Le service influxdb lance un conteneur Docker basé sur l’image officielle influxdb en version 1.8.2, attache le volume influxdb-data au point de montage /var/lib/influxdb permettant la persistance des données, et expose le port 8086 dans le réseau speedtest permettant une communication interne dans ce réseau via le hostname influxdb.

Les versions d’images ont été pinnées majeur.mineur.patch pour faciliter le suivi de la partie pratique en éliminant les soucis de compatibilité des futures versions, mais rien n’oblige à rester sur ces versions si les compatibilités sont vérifiées.

Démarrons maintenant cette stack docker-compose avec la commande :

docker-compose up -d

Puis vérifions que vos 2 conteneurs sont bien au statut Up avec la commande.

docker-compose ps

        Name                  Command           State    Ports

----------------------------------------------------------------

speedtest_grafana_1    /run.sh                  Up      3000/tcp

speedtest_influxdb_1   /entrypoint.sh influxd   Up      8086/tcp

Maintenant que notre stack stockage et visualisation est démarrée, intéressons-nous à la partie récupération des métriques.

RÉCUPÉRATION DES MÉTRIQUES

Comme annoncé précédemment, nous allons ici utiliser notre propre image Docker embarquant speedtest-cli.

DOCKER ENTRYPOINT

Commençons par créer notre script bash servant d’entrypoint Docker et qui sera en charge de l’exécution de speedtest-cli, de l’extraction des informations qui nous intéressent, puis de l’envoi des métriques à InfluxDB.

./docker-entrypoint.sh

#!/usr/bin/env bash

# InfluxDB variables

influxdb_proto=${INFLUXDB_PROTO:-http}

influxdb_host=${INFLUXDB_HOST:-influxdb}

influxdb_port=${INFLUXDB_PORT:-8086}

influxdb_db=${INFLUXDB_DB:-speedtest}

influxdb_url="${influxdb_proto}://${influxdb_host}:${influxdb_port}"

# run speedtest & store result

json_result=$(speedtest -f json --accept-license --accept-gdpr)

# Extract data from speedtest result

result_id=$(echo "${json_result}" | jq -r '.result.id')

ping_latency=$(echo "${json_result}" | jq -r '.ping.latency')

download_bandwidth=$(echo "${json_result}" | jq -r '.download.bandwidth')

upload_bandwidth=$(echo "${json_result}" | jq -r '.upload.bandwidth')

# Ensure InfluxDB database exists

curl \

    -d "q=CREATE DATABASE ${influxdb_db}" \

    "${influxdb_url}/query"

# Write metric to InfluxDB

curl \

    -d "speedtest,result_id=${result_id} ping_latency=${ping_latency},download_bandwidth=${download_bandwidth},upload_bandwidth=${upload_bandwidth}" \

    "${influxdb_url}/write?db=${influxdb_db}"

On commence par définir les variables permettant la communication avec InfluxDB :

L’ensemble de ces variables étant ensuite concaténé afin de produire l’url permettant la communication avec InfluxDB

Ensuite on stocke dans une variable le résultat de la commande speedtest exécutée avec les options et arguments :

Une fois notre résultat récupéré, nous utilisons l’utilitaire jq pour extraire les informations qui nous intéressent :

Maintenant que nous avons toutes les informations qui nous intéressent dans des variables, assurons-nous que la base de données InfluxDB speedtest existe en forçant la création si celle-ci n’existe pas en exécutant la query CREATE DATABASE ${influx_db} sur le endpoint /query d’InfluxDB.

Puis pour finir écrivons dans cette base de données nos résultats sur le endpoint /write d’InfluxDB en précisant le nom de notre base de données ?db=${influxdb_db}, avec la data speedtest,result_id=${result_id} ping_latency=${ping_latency},download_bandwidth=${download_bandwidth},upload_bandwidth=${upload_bandwidth}

Plus d’informations sur l’écriture dans InfluxDB sont disponibles dans la documentation officielle

Ajoutons ensuite les droits d’exécution sur ce script avec la commande sudo chmod +x ./docker-entrypoint.sh.

Notre entrypoint est prêt, passons maintenant à la création de l’image Docker responsable de l’exécution de ce script

DOCKERFILE

La documentation d’installation de speedtest-cli donne des instructions pour Debian, nous allons donc partir d’une image debian pour créer la nôtre et nous inspirer de cette documentation d’installation en l’adaptant à notre cas.

./Dockerfile

FROM debian:buster-slim

ENV INSTALL_KEY 379CE192D401AB61

ENV DEB_DISTRO buster

# install requirements curl & jq

RUN apt-get update && apt-get install -y curl jq

# install speedtest

RUN apt-get update && apt-get install -y gnupg1 apt-transport-https dirmngr && \

        apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $INSTALL_KEY && \

        echo "deb https://ookla.bintray.com/debian ${DEB_DISTRO} main" | tee /etc/apt/sources.list.d/speedtest.list && \

        apt-get update && \

        apt-get install speedtest

COPY docker-entrypoint.sh /usr/local/bin

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]

Nous partons donc d’une image officielle debian en version buster-slim, la slim étant largement suffisante pour notre projet tout en préservant l’espace disque si précieux de notre raspberry pi.

Définissons ensuite quelques variables d’environnements :

On installe ensuite les paquets requis (curljq) par notre script bash d’entrypoint.

Ensuite on installe speedtest-cli, inspirée par la documentation d’installation speedtest-cli mais adaptée pour docker.

Et pour finir on copie notre script bash docker-entrypoint.sh, dans l’image et on indique que ce script sert d’entrypoint.

Passons au build de notre image Docker avec la commande

docker build -t docker.local/speedtest:buster-slim .

Notre système de récupération, extraction et écriture étant prêt, passons maintenant à la planification de cette taâche.

CRON JOB

Après de multiples tests de résolution (toutes les heures, toutes les demi-heures, toutes les minutes, …), je me suis arrêté sur une mesure toutes les 10 minutes qui permet une bonne visibilité sans trop charger le réseau. Pour cela nous allons ajouter un cron job sur notre raspberry pi.

Utilisez la commande

crontab -e

Et ajoutez en fin de fichier la ligne suivante avant de sauvegarder

*/10 * * * * /usr/bin/docker run --rm --network speedtest docker.local/speedtest:buster-slim

Cela signifie que toutes les 10 minutes (*/10 * * * *), la commande /usr/bin/docker run --rm --network speedtest docker.local/speedtest:latest sera exécutée. Cette commande ayant pour responsabilité de démarrer un conteneur Docker depuis l’image précédemment créée docker.local/speedtest:latest dans le réseau speedtest (pour la communication avec influxdb) puis de supprimer le conteneur (--rm) une fois l’exécution terminée.

CONFIGURATION DE GRAFANA

La dernière étape de notre projet consiste à configurer notre Grafana en :

CONNEXION À L’INTERFACE WEB

Pour vous connecter a l’interface web de Grafana, rendez vous à l’url http://<ip_raspberry_pi>:3000/.

Un écran de connexion s’affiche, utilisez le username admin et le mot de passe admin pour votre première connexion. Vous serez ensuite redirigé vers une page vous permettant de changer le mot de passe de l’utilisateur admin.