Ein TIG-Stack mit Docker Compose liefert Ihnen eine vollständige MQTT-Datenpipeline auf einem einzigen Rechner: Telegraf abonniert Ihren Broker, InfluxDB speichert die Messwerte und Grafana stellt sie dar. In diesem Leitfaden erstellen Sie jede benötigte Datei, starten den Stack mit einem Befehl und öffnen in Grafana ein Dashboard, das bereits provisioniert ist und Live-Daten zeigt.
Was Sie bauen
Der Stack besteht aus drei Containern und einer externen Abhängigkeit, dem MQTT-Broker:
devices / simulator --> MQTT broker (broker.connectmq.com)
|
Telegraf (mqtt_consumer)
|
InfluxDB 2 (bucket "sensors")
|
Grafana (provisioned data source + dashboard)
Der Broker bleibt bewusst außerhalb von Compose. Broker sind langlebige Infrastruktur, die sich viele Consumer teilen; der TIG-Stack ist einer dieser Consumer. Telegraf verbindet sich als gewöhnlicher MQTT-Client mit dem Broker, was für den öffentlichen MQTT-Broker und für einen privaten Broker gleich funktioniert.
Warum Docker Compose für den TIG-Stack?
Jedes der drei Werkzeuge lässt sich nativ installieren, doch das bedeutet drei Paketquellen, drei Service-Definitionen und über das System verstreute Konfigurationsdateien. Compose bündelt die gesamte Pipeline in einem Ordner, den Sie versionieren, auf einen anderen Rechner kopieren oder spurlos abbauen können. Außerdem werden Versionen explizit festgelegt, sodass ein Betriebssystem-Update InfluxDB oder Grafana nie hinter Ihrem Rücken aktualisiert.
Der Kompromiss: Compose ist ein Werkzeug für einen einzelnen Host. Es passt gut zu einem Entwicklungs-Laptop, einem Labor, einem kleinen Standort-Gateway oder einem On-Premises-Server, der Daten aus einem Werk sammelt. Hochverfügbarkeit bietet es nicht; fällt der Host aus, fällt auch der Stack aus. Für viele Monitoring-Anwendungsfälle ist das akzeptabel, denn die Geräte veröffentlichen weiter an den Broker und Telegraf macht weiter, sobald es zurück ist; und wenn Sie Telegraf auf QoS 1 mit persistent_session = true umstellen, kann der Broker dessen Nachrichten während eines kurzen Ausfalls vorhalten.
Projektstruktur
Legen Sie diese Verzeichnisstruktur an:
tig-mqtt/
.env
docker-compose.yml
telegraf/
telegraf.conf
grafana/
provisioning/
datasources/
influxdb.yml
dashboards/
dashboards.yml
dashboards/
mqtt-sensors.json
Insgesamt sechs Dateien. Jede wird unten vollständig gezeigt.
Schritt 1: Umgebungsvariablen
Geheimnisse und Namen liegen in .env, das Docker Compose automatisch einliest. Halten Sie diese Datei aus der Versionsverwaltung heraus.
# .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=
Erzeugen Sie ein echtes Token mit openssl rand -hex 32. Ersetzen Sie a1b2c3 durch Ihre eigene zufällige Zeichenfolge, damit Ihre Topics auf dem öffentlichen MQTT-Broker getrennt bleiben. Der öffentliche MQTT-Broker ist nur für Tests und Prototypen gedacht, nicht für Produktivdaten.
Schritt 2: Die Docker-Compose-Datei für den TIG-Stack
# 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:
Der Healthcheck ist wichtig. Ohne ihn kann Telegraf starten, bevor InfluxDB die Ersteinrichtung abgeschlossen hat, bei den ersten Schreibvorgängen scheitern und die Logs mit Fehlern füllen. condition: service_healthy lässt Compose warten, bis influx ping erfolgreich ist.
Schritt 3: Telegraf-Konfiguration
Telegraf ersetzt ${VAR}-Verweise aus seiner Umgebung, die Konfigurationsdatei enthält also keine Geheimnisse.
# 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}"
Beachten Sie die URL http://influxdb:8086: Innerhalb des Compose-Netzwerks erreichen sich Container über den Service-Namen, nicht über localhost. Das tags-Muster setzt ein dreistufiges Präfix wie connectmq/demo/a1b2c3 voraus; hat Ihr Präfix eine andere Tiefe, passen Sie die Anzahl der führenden Unterstriche an. Eine zeilenweise Erklärung dieser Optionen finden Sie im Leitfaden zum Telegraf MQTT Consumer.
Schritt 4: Die Grafana-Datenquelle provisionieren
Die Provisionierung legt die InfluxDB-Datenquelle beim Start an, sodass sich niemand durch die Oberfläche klicken muss. Grafana expandiert Umgebungsvariablen auch in Provisionierungsdateien.
# 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}
Die feste uid erlaubt es dem Dashboard, zuverlässig auf diese Datenquelle zu verweisen.
Schritt 5: Ein fertiges Dashboard provisionieren
Teilen Sie Grafana zuerst mit, wo die Dashboards liegen:
# grafana/provisioning/dashboards/dashboards.yml
apiVersion: 1
providers:
- name: mqtt
folder: MQTT
type: file
options:
path: /var/lib/grafana/dashboards
Fügen Sie dann das Dashboard selbst hinzu. Es enthält eine Temperatur-Zeitreihe pro Gerät und ein Stat-Panel mit der Anzahl der meldenden Geräte.
{
"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()"
}
]
}
]
}
Wenn Sie den Bucket-Namen in .env geändert haben, ändern Sie "sensors" auch in den beiden Abfragen. Sie können dieses JSON auch in jeder bestehenden Grafana-Instanz über Dashboards, dann New, dann Import einspielen.
Schritt 6: Den Stack starten und Daten senden
cd tig-mqtt
docker compose up -d
docker compose ps
docker compose logs -f telegraf
Veröffentlichen Sie nun Daten. Die schnellste kontinuierliche Quelle ist unser Python-MQTT-Gerätesimulator; starten Sie ihn mit --prefix connectmq/demo/a1b2c3, damit er zu MQTT_TOPIC_PREFIX passt. Eine einzelne Testnachricht funktioniert ebenfalls:
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}"
Öffnen Sie http://localhost:3000, melden Sie sich als admin mit GRAFANA_PASSWORD an und öffnen Sie das Dashboard MQTT Sensors im Ordner MQTT.
Jede Schicht der Reihe nach prüfen
Wenn das Dashboard leer bleibt, widerstehen Sie dem Drang, mehrere Dinge gleichzeitig zu ändern. Gehen Sie die Pipeline hinunter und bestätigen Sie jede Schicht, bevor Sie zur nächsten wechseln:
- Broker. Führen Sie
mosquitto_sub -h broker.connectmq.com -p 1883 -i check-a1b2c3 -t "connectmq/demo/a1b2c3/#" -vaus. Erscheint nichts, liegt das Problem beim Publisher, nicht beim Stack. - Telegraf-Verbindung.
docker compose logs telegrafsollte zeigen, dass sich das Plugin fehlerfrei verbindet. Authentifizierungsfehler und Topic-Parsing-Fehler erscheinen hier. - Telegraf-Parsing. Fügen Sie vorübergehend einen
[[outputs.file]]-Block mitfiles = ["stdout"]hinzu und starten Sie Telegraf neu. Geparste Metriken erscheinen dann als Line Protocol in den Logs, was beweist, dass JSON- und Topic-Mapping stimmen. - InfluxDB. Führen Sie
docker compose exec influxdb influx query 'from(bucket: "sensors") |> range(start: -5m) |> limit(n: 3)'aus. Die CLI im Container ist durch das Init-Setup bereits konfiguriert. - Grafana. Öffnen Sie die Seite der Datenquelle und klicken Sie auf Save and test; prüfen Sie dann, ob der Zeitraum des Dashboards die Zeit abdeckt, in der Daten geschrieben wurden.
In der Praxis werden die meisten Probleme in Schritt 1 oder Schritt 3 gefunden: ein Topic-Präfix, das sich um ein Zeichen unterscheidet, oder eine Payload, die nicht das JSON ist, das die Konfiguration erwartet.
Fallstricke beim ersten Start
| Problem | Ursache | Lösung |
|---|---|---|
Token aus .env wird abgelehnt |
InfluxDB-Init-Variablen gelten nur für ein leeres Volume | Mit docker compose down -v zurücksetzen oder in der Oberfläche ein neues Token erstellen |
| Telegraf: connection refused zu localhost:8086 | Falscher Hostname innerhalb der Container | http://influxdb:8086 verwenden |
| Dashboard zeigt "No data" | Topic-Präfix in .env weicht vom Veröffentlichten ab |
Mit mosquitto_sub -t "connectmq/demo/a1b2c3/#" -v vergleichen |
| Telegraf: Topic-Parsing-Fehler | Präfixtiefe geändert, tags-Muster aber nicht |
Anzahl der _-Segmente an die Topic-Ebenen anpassen |
| Fehler bei der Grafana-Datenquelle | Token oder Org passen nicht | Seite der Datenquelle prüfen; die Werte stammen aus .env |
Stack funktioniert, aber Daten verschwinden nach down -v |
Volumes gelöscht | docker compose down ohne -v verwenden |
Wechsel zu einem privaten Broker
Für echte Anlagen ändert sich nur .env. Richten Sie den Stack auf einen verwalteten MQTT-Broker wie 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
Folgt Ihr Werk einem Unified Namespace (UNS) nach ISA-95, etwa acme/werk-stuttgart/montage/linie-1/..., setzen Sie MQTT_TOPIC_PREFIX auf den Teilbaum des Standorts und passen das tags-Muster an die zusätzlichen Ebenen an; so landen Area und Linie direkt als Tags in InfluxDB.
Das Zertifikat stammt von Let's Encrypt, Telegraf vertraut ihm also ohne zusätzliche TLS-Einstellungen. Führen Sie erneut docker compose up -d aus, um den Telegraf-Container mit den neuen Werten neu zu erstellen. Stellen Sie Grafana außerdem hinter einen Reverse Proxy mit HTTPS, bevor Sie es über Ihren Rechner hinaus erreichbar machen, und sichern Sie das Volume influxdb-data.
Wenn das Dashboard steht, ergänzen Sie Grafana-Alarme für IoT-Sensordaten auf denselben Abfragen. Für eine breitere Auswahl an Clients auf der Geräteseite siehe den Leitfaden zu MQTT-Client-Bibliotheken; die Docker-Compose-Dokumentation behandelt Healthchecks und Umgebungsdateien im Detail.
Starten Sie mit ConnectMQ
Nutzen Sie den öffentlichen MQTT-Broker, um den Stack noch heute mit simulierten Daten hochzufahren. Für die Produktion betreibt ConnectMQ einen vollständig verwalteten MQTT-Broker mit TLS, MQTT 5 und einem Portal, in dem Sie Topics live beobachten können, bevor Telegraf sie überhaupt sieht. Erstellen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker ohne Kreditkarte und fügen Sie die Zugangsdaten in .env ein. Wenn Sie Hosting-Optionen abwägen, lesen Sie unseren Leitfaden zum Cloud-MQTT-Broker.
Häufig gestellte Fragen
Kann ich den MQTT-Broker in derselben Docker-Compose-Datei betreiben?
Das ist möglich, doch ein gemeinsam genutzter, verwalteter MQTT-Broker ist meist einfacher zu betreiben und erlaubt anderen Consumern, dieselben Daten zu nutzen. Ihn außerhalb von Compose zu halten bedeutet außerdem, dass ein Neustart des Stacks Ihre Geräte nie unterbricht.
Funktioniert dieses TIG-Stack-Setup mit Docker Compose auch mit InfluxDB 3?
Nicht unverändert. InfluxDB 3 verwendet ein anderes Image, ein anderes Einrichtungsverfahren und andere Abfragesprachen; die Init-Variablen und Flux-Abfragen hier gelten für InfluxDB 2.7.
Wie füge ich weitere Dashboards hinzu?
Legen Sie zusätzliche Dashboard-JSON-Dateien in grafana/dashboards ab. Grafana übernimmt sie über den File-Provider automatisch.
Wie viel Speicherplatz belegen die Daten?
Das hängt von der Anzahl der Serien und der Nachrichtenrate ab. Die 30-tägige Aufbewahrung des Buckets begrenzt das Wachstum; senken Sie sie oder führen Sie ein Downsampling älterer Daten durch, wenn der Speicher knapp ist.



