Tutoriels IoT

Stack TIG avec Docker Compose pour les données MQTT

Une configuration docker-compose complète pour Telegraf, InfluxDB 2 et Grafana qui s'abonne à un broker MQTT, stocke les données de capteurs et s'ouvre sur une source de données et un tableau de bord provisionnés, avec les pièges qui font échouer les premiers lancements.

Schéma d'une stack TIG Docker Compose avec Telegraf lisant des topics MQTT, InfluxDB stockant les métriques et des tableaux de bord Grafana
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Une stack TIG avec Docker Compose vous offre un pipeline de données MQTT complet sur une seule machine : Telegraf s'abonne à votre broker, InfluxDB stocke les mesures et Grafana les affiche en graphiques. Dans ce guide, vous allez créer tous les fichiers nécessaires, démarrer la stack d'une seule commande et ouvrir Grafana sur un tableau de bord déjà provisionné qui affiche des données en direct.

Ce que vous allez construire

La stack comporte trois conteneurs et une dépendance externe, le broker MQTT :

devices / simulator --> MQTT broker (broker.connectmq.com)
                              |
                         Telegraf (mqtt_consumer)
                              |
                         InfluxDB 2 (bucket "sensors")
                              |
                         Grafana (provisioned data source + dashboard)

Le broker reste volontairement en dehors de Compose. Les brokers sont une infrastructure pérenne partagée par de nombreux consommateurs ; la stack TIG n'est que l'un d'entre eux. Telegraf se connecte au broker comme un client MQTT ordinaire, ce qui fonctionne de la même façon avec le serveur MQTT public gratuit et avec un broker privé.

Pourquoi Docker Compose pour la stack TIG

Chacun des trois outils peut être installé nativement, mais cela implique trois dépôts de paquets, trois définitions de services et des fichiers de configuration éparpillés sur le système. Compose réunit tout le pipeline dans un seul dossier que vous pouvez versionner, copier sur une autre machine ou supprimer sans laisser de traces. Il fixe aussi explicitement les versions, si bien qu'une mise à jour du système d'exploitation ne met jamais à niveau InfluxDB ou Grafana dans votre dos.

La contrepartie est que Compose est un outil mono-hôte. Il convient bien à un ordinateur de développement, un laboratoire, une petite passerelle de site ou un serveur sur site qui collecte les données d'une usine. Il n'offre pas de haute disponibilité : si l'hôte tombe, la stack aussi. Pour de nombreux cas de supervision, c'est acceptable, car les appareils continuent de publier vers le broker et Telegraf reprend à son retour ; et si vous passez Telegraf en QoS 1 avec persistent_session = true, le broker peut conserver ses messages pendant une courte interruption.

Organisation du projet

Créez cette arborescence :

tig-mqtt/
  .env
  docker-compose.yml
  telegraf/
    telegraf.conf
  grafana/
    provisioning/
      datasources/
        influxdb.yml
      dashboards/
        dashboards.yml
    dashboards/
      mqtt-sensors.json

Six fichiers au total. Chacun est présenté intégralement ci-dessous.

Étape 1 : variables d'environnement

Les secrets et les noms se trouvent dans .env, que Docker Compose lit automatiquement. Tenez-le à l'écart du contrôle de version.

# .env
INFLUX_USERNAME=admin
INFLUX_PASSWORD=change-me-please
INFLUX_ORG=iot
INFLUX_BUCKET=sensors
INFLUX_TOKEN=replace-with-a-long-random-token
GRAFANA_PASSWORD=change-me-too

MQTT_SERVER=tcp://broker.connectmq.com:1883
MQTT_TOPIC_PREFIX=connectmq/demo/a1b2c3
MQTT_CLIENT_ID=telegraf-a1b2c3
MQTT_USERNAME=
MQTT_PASSWORD=

Générez un vrai token avec openssl rand -hex 32. Remplacez a1b2c3 par votre propre chaîne aléatoire pour que vos topics restent séparés sur le broker public.

Étape 2 : le fichier Docker Compose de la stack TIG

# docker-compose.yml
services:
  influxdb:
    image: influxdb:2.7
    restart: unless-stopped
    ports:
      - "8086:8086"
    environment:
      DOCKER_INFLUXDB_INIT_MODE: setup
      DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUX_USERNAME}
      DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUX_PASSWORD}
      DOCKER_INFLUXDB_INIT_ORG: ${INFLUX_ORG}
      DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUX_BUCKET}
      DOCKER_INFLUXDB_INIT_RETENTION: 30d
      DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUX_TOKEN}
    volumes:
      - influxdb-data:/var/lib/influxdb2
      - influxdb-config:/etc/influxdb2
    healthcheck:
      test: ["CMD", "influx", "ping"]
      interval: 10s
      timeout: 5s
      retries: 12

  telegraf:
    image: telegraf:1.32
    restart: unless-stopped
    depends_on:
      influxdb:
        condition: service_healthy
    environment:
      INFLUX_TOKEN: ${INFLUX_TOKEN}
      INFLUX_ORG: ${INFLUX_ORG}
      INFLUX_BUCKET: ${INFLUX_BUCKET}
      MQTT_SERVER: ${MQTT_SERVER}
      MQTT_TOPIC_PREFIX: ${MQTT_TOPIC_PREFIX}
      MQTT_CLIENT_ID: ${MQTT_CLIENT_ID}
      MQTT_USERNAME: ${MQTT_USERNAME}
      MQTT_PASSWORD: ${MQTT_PASSWORD}
    volumes:
      - ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro

  grafana:
    image: grafana/grafana:11.3.0
    restart: unless-stopped
    depends_on:
      - influxdb
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
      INFLUX_TOKEN: ${INFLUX_TOKEN}
      INFLUX_ORG: ${INFLUX_ORG}
      INFLUX_BUCKET: ${INFLUX_BUCKET}
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
      - ./grafana/dashboards:/var/lib/grafana/dashboards:ro

volumes:
  influxdb-data:
  influxdb-config:
  grafana-data:

Le health check est important. Sans lui, Telegraf peut démarrer avant qu'InfluxDB ait terminé sa configuration initiale, échouer ses premières écritures et remplir les journaux d'erreurs. condition: service_healthy fait attendre Compose jusqu'à ce que influx ping réussisse.

Étape 3 : configuration de Telegraf

Telegraf substitue les références ${VAR} à partir de son environnement : le fichier de configuration ne contient donc aucun secret.

# telegraf/telegraf.conf
[agent]
  interval = "10s"
  flush_interval = "10s"
  omit_hostname = true

[[inputs.mqtt_consumer]]
  servers = ["${MQTT_SERVER}"]
  topics = ["${MQTT_TOPIC_PREFIX}/+/+/telemetry"]
  qos = 0
  client_id = "${MQTT_CLIENT_ID}"
  username = "${MQTT_USERNAME}"
  password = "${MQTT_PASSWORD}"

  name_override = "sensor"
  topic_tag = ""
  data_format = "json"
  tag_keys = ["device"]
  json_time_key = "ts"
  json_time_format = "unix_ms"

  [[inputs.mqtt_consumer.topic_parsing]]
    topic = "${MQTT_TOPIC_PREFIX}/+/+/telemetry"
    tags = "_/_/_/line/_/_"

[[outputs.influxdb_v2]]
  urls = ["http://influxdb:8086"]
  token = "${INFLUX_TOKEN}"
  organization = "${INFLUX_ORG}"
  bucket = "${INFLUX_BUCKET}"

Notez l'URL http://influxdb:8086 : au sein du réseau Compose, les conteneurs se joignent par nom de service, et non via localhost. Le motif tags suppose un préfixe à trois niveaux comme connectmq/demo/a1b2c3 ; si votre préfixe a une profondeur différente, ajustez le nombre de tirets bas initiaux. Pour une explication ligne par ligne de ces options, consultez le guide Telegraf MQTT consumer.

Étape 4 : provisionner la source de données Grafana

Le provisioning crée la source de données InfluxDB au démarrage, sans que personne ait à cliquer dans l'interface. Grafana développe aussi les variables d'environnement dans les fichiers de provisioning.

# grafana/provisioning/datasources/influxdb.yml
apiVersion: 1
datasources:
  - name: InfluxDB
    uid: influxdb
    type: influxdb
    access: proxy
    url: http://influxdb:8086
    isDefault: true
    jsonData:
      version: Flux
      organization: ${INFLUX_ORG}
      defaultBucket: ${INFLUX_BUCKET}
    secureJsonData:
      token: ${INFLUX_TOKEN}

L'uid fixe permet au tableau de bord de référencer cette source de données de manière fiable.

Étape 5 : provisionner un tableau de bord prêt à l'emploi

Indiquez d'abord à Grafana où se trouvent les tableaux de bord :

# grafana/provisioning/dashboards/dashboards.yml
apiVersion: 1
providers:
  - name: mqtt
    folder: MQTT
    type: file
    options:
      path: /var/lib/grafana/dashboards

Ajoutez ensuite le tableau de bord lui-même. Il contient une série temporelle de température par appareil et un panneau Stat indiquant le nombre d'appareils qui remontent des données.

{
  "uid": "mqtt-sensors",
  "title": "MQTT Sensors",
  "schemaVersion": 39,
  "refresh": "10s",
  "time": { "from": "now-1h", "to": "now" },
  "panels": [
    {
      "id": 1,
      "type": "timeseries",
      "title": "Temperature by device",
      "gridPos": { "x": 0, "y": 0, "w": 18, "h": 10 },
      "datasource": { "type": "influxdb", "uid": "influxdb" },
      "fieldConfig": { "defaults": { "unit": "celsius" }, "overrides": [] },
      "targets": [
        {
          "refId": "A",
          "query": "from(bucket: \"sensors\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r._measurement == \"sensor\" and r._field == \"temperature\")\n  |> group(columns: [\"device\"])\n  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)"
        }
      ]
    },
    {
      "id": 2,
      "type": "stat",
      "title": "Reporting devices (last 5 min)",
      "gridPos": { "x": 18, "y": 0, "w": 6, "h": 10 },
      "datasource": { "type": "influxdb", "uid": "influxdb" },
      "targets": [
        {
          "refId": "A",
          "query": "from(bucket: \"sensors\")\n  |> range(start: -5m)\n  |> filter(fn: (r) => r._measurement == \"sensor\" and r._field == \"temperature\")\n  |> group()\n  |> distinct(column: \"device\")\n  |> count()"
        }
      ]
    }
  ]
}

Si vous avez changé le nom du bucket dans .env, modifiez aussi "sensors" dans les deux requêtes. Vous pouvez également importer ce JSON via Dashboards, puis New, puis Import dans n'importe quelle instance Grafana existante.

Étape 6 : démarrer la stack et envoyer des données

cd tig-mqtt
docker compose up -d
docker compose ps
docker compose logs -f telegraf

Publiez maintenant des données. La source continue la plus rapide est notre simulateur d'appareils MQTT en Python ; lancez-le avec --prefix connectmq/demo/a1b2c3 pour qu'il corresponde à MQTT_TOPIC_PREFIX. Un simple message de test fonctionne aussi :

mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-a1b2c3 \
  -t connectmq/demo/a1b2c3/line1/sensor-0001/telemetry \
  -m "{\"device\":\"sensor-0001\",\"ts\":$(date +%s%3N),\"temperature\":22.4,\"humidity\":41.0}"

Ouvrez http://localhost:3000, connectez-vous en tant qu'admin avec GRAFANA_PASSWORD et ouvrez le tableau de bord MQTT Sensors dans le dossier MQTT.

Vérifier chaque couche dans l'ordre

Quand le tableau de bord reste vide, résistez à l'envie de modifier plusieurs choses à la fois. Descendez le long du pipeline et validez chaque couche avant de passer à la suivante :

  1. Broker. Lancez mosquitto_sub -h broker.connectmq.com -p 1883 -i check-a1b2c3 -t "connectmq/demo/a1b2c3/#" -v. Si rien n'apparaît, le problème vient du publisher, pas de la stack.
  2. Connexion de Telegraf. docker compose logs telegraf doit montrer le plugin se connecter sans erreur. Les échecs d'authentification et les erreurs de topic parsing apparaissent ici.
  3. Parsing de Telegraf. Ajoutez temporairement un bloc [[outputs.file]] avec files = ["stdout"] et redémarrez Telegraf. Les métriques parsées apparaissent alors dans les journaux en line protocol, ce qui prouve que le JSON et le mapping des topics sont corrects.
  4. InfluxDB. Lancez docker compose exec influxdb influx query 'from(bucket: "sensors") |> range(start: -5m) |> limit(n: 3)'. La CLI du conteneur est déjà configurée par l'initialisation.
  5. Grafana. Ouvrez la page de la source de données et cliquez sur Save and test, puis vérifiez que la plage de temps du tableau de bord couvre la période où les données ont été écrites.

En pratique, la plupart des problèmes se trouvent à l'étape 1 ou à l'étape 3 : un préfixe de topic qui diffère d'un caractère, ou un payload qui n'est pas le JSON attendu par la configuration.

Les pièges du premier lancement

Problème Cause Correction
Token de .env rejeté Les variables d'initialisation d'InfluxDB ne s'appliquent qu'à un volume vide docker compose down -v pour réinitialiser, ou créer un nouveau token dans l'interface
Telegraf : connexion refusée vers localhost:8086 Mauvais nom d'hôte à l'intérieur des conteneurs Utiliser http://influxdb:8086
Le tableau de bord affiche « No data » Le préfixe de topic de .env diffère de ce qui est publié Comparer avec mosquitto_sub -t "connectmq/demo/a1b2c3/#" -v
Telegraf : erreur de topic parsing La profondeur du préfixe a changé mais pas le motif tags Faire correspondre le nombre de segments _ aux niveaux du topic
Erreur de la source de données Grafana Token ou org incohérents Vérifier la page de la source de données ; les valeurs proviennent de .env
La stack fonctionne, mais les données disparaissent après down -v Volumes supprimés Utiliser docker compose down sans -v

Passer à un broker privé

Pour de vrais équipements, seul .env change. Pointez la stack vers un broker MQTT managé comme ConnectMQ :

MQTT_SERVER=ssl://broker.connectmq.com:8883
MQTT_TOPIC_PREFIX=connectmq/factory1/production
MQTT_CLIENT_ID=YOUR_CLIENT_ID
MQTT_USERNAME=YOUR_USERNAME
MQTT_PASSWORD=YOUR_PASSWORD

Le certificat est délivré par Let's Encrypt : Telegraf lui fait donc confiance sans paramètre TLS supplémentaire. Relancez docker compose up -d pour recréer le conteneur Telegraf avec les nouvelles valeurs. Placez aussi Grafana derrière un reverse proxy en HTTPS avant de l'exposer au-delà de votre machine, et sauvegardez le volume influxdb-data.

Une fois le tableau de bord en place, ajoutez des alertes Grafana sur les données de capteurs IoT à partir des mêmes requêtes. Pour un choix plus large de clients côté appareil, consultez le guide des bibliothèques clientes MQTT, et la documentation de Docker Compose détaille les health checks et les fichiers d'environnement.

Démarrez avec ConnectMQ

Utilisez le serveur MQTT public gratuit pour lancer la stack dès aujourd'hui avec des données simulées. Pour la production, ConnectMQ exploite un broker MQTT managé avec TLS, MQTT 5 et un portail où vous pouvez observer les topics en direct avant même que Telegraf ne les voie. Créez un broker Serverless gratuit sur app.connectmq.com sans carte bancaire, puis collez les identifiants dans .env. Si vous comparez les options d'hébergement, lisez notre guide du broker MQTT cloud.

Questions fréquentes

Puis-je exécuter le broker MQTT dans le même fichier Docker Compose ?

C'est possible, mais un broker MQTT managé et partagé est généralement plus simple à exploiter et permet à d'autres consommateurs d'utiliser les mêmes données. Le garder hors de Compose garantit aussi qu'un redémarrage de la stack n'interrompt jamais vos appareils.

Cette configuration de stack TIG Docker Compose fonctionne-t-elle avec InfluxDB 3 ?

Pas en l'état. InfluxDB 3 utilise une image, une procédure d'installation et des langages de requête différents : les variables d'initialisation et les requêtes Flux présentées ici s'appliquent à InfluxDB 2.7.

Comment ajouter d'autres tableaux de bord ?

Déposez des fichiers JSON de tableaux de bord supplémentaires dans grafana/dashboards. Grafana les prend en compte automatiquement via le file provider.

Quel espace disque les données vont-elles occuper ?

Cela dépend du nombre de séries et du débit de messages. La rétention de 30 jours du bucket limite la croissance ; réduisez-la ou sous-échantillonnez les données anciennes si l'espace disque est restreint.

Articles liés

Les meilleurs outils CLI MQTT pour tester, scripter et déboguer

Un comparatif pratique de mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, la CLI MQTT.js, curl et mqttui, avec le même test exécuté sur le serveur MQTT public gratuit broker.connectmq.com pour choisir le bon outil pour le scripting et le débogage.

9 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.