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 :
- 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. - Connexion de Telegraf.
docker compose logs telegrafdoit montrer le plugin se connecter sans erreur. Les échecs d'authentification et les erreurs de topic parsing apparaissent ici. - Parsing de Telegraf. Ajoutez temporairement un bloc
[[outputs.file]]avecfiles = ["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. - 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. - 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.



