Uma stack TIG com Docker Compose entrega um pipeline completo de dados MQTT em uma única máquina: o Telegraf assina o seu broker, o InfluxDB armazena as leituras e o Grafana as transforma em gráficos. Neste guia você vai criar todos os arquivos necessários, subir a stack com um único comando e abrir o Grafana em um dashboard já provisionado e exibindo dados ao vivo.
O que você vai construir
A stack tem três contêineres e uma dependência externa, o broker MQTT:
devices / simulator --> MQTT broker (broker.connectmq.com)
|
Telegraf (mqtt_consumer)
|
InfluxDB 2 (bucket "sensors")
|
Grafana (provisioned data source + dashboard)
O broker fica fora do Compose de propósito. Brokers são infraestrutura de longa duração compartilhada por muitos consumidores; a stack TIG é apenas um deles. O Telegraf se conecta ao broker como um cliente MQTT comum, o que funciona igual para o servidor MQTT público de testes e para um broker privado.
Por que usar Docker Compose para a stack TIG
Cada uma das três ferramentas pode ser instalada nativamente, mas isso significa três repositórios de pacotes, três definições de serviço e arquivos de configuração espalhados pelo sistema. O Compose coloca o pipeline inteiro em uma única pasta que você pode versionar, copiar para outra máquina ou remover sem deixar rastros. Ele também fixa as versões explicitamente, então uma atualização do sistema operacional nunca atualiza o InfluxDB ou o Grafana pelas suas costas.
A contrapartida é que o Compose é uma ferramenta de host único. Ele se encaixa bem em um notebook de desenvolvimento, um laboratório, um gateway de uma pequena unidade ou um servidor on-premises que coleta dados de uma fábrica. Ele não oferece alta disponibilidade; se o host cair, a stack cai junto. Para muitos casos de monitoramento isso é aceitável, porque os dispositivos continuam publicando no broker e o Telegraf retoma quando volta, e se você passar o Telegraf para QoS 1 com persistent_session = true, o broker pode guardar as mensagens dele durante uma interrupção curta.
Estrutura do projeto
Crie esta estrutura de diretórios:
tig-mqtt/
.env
docker-compose.yml
telegraf/
telegraf.conf
grafana/
provisioning/
datasources/
influxdb.yml
dashboards/
dashboards.yml
dashboards/
mqtt-sensors.json
São seis arquivos no total. Cada um aparece completo a seguir.
Passo 1: variáveis de ambiente
Segredos e nomes ficam no .env, que o Docker Compose lê automaticamente. Mantenha-o fora do controle de versão.
# .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=
Gere um token de verdade com openssl rand -hex 32. Substitua a1b2c3 por uma string aleatória sua para que os seus topics fiquem separados no servidor MQTT público.
Passo 2: o arquivo Docker Compose da 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:
O health check é importante. Sem ele, o Telegraf pode iniciar antes de o InfluxDB terminar a configuração da primeira execução, falhar nas primeiras gravações e encher os logs de erros. O condition: service_healthy faz o Compose esperar até que o influx ping tenha sucesso.
Passo 3: configuração do Telegraf
O Telegraf substitui as referências ${VAR} a partir do seu ambiente, então o arquivo de configuração não contém segredos.
# 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}"
Repare na URL http://influxdb:8086: dentro da rede do Compose, os contêineres se encontram pelo nome do serviço, e não por localhost. O padrão de tags pressupõe um prefixo de três níveis como connectmq/demo/a1b2c3; se o seu prefixo tiver outra profundidade, ajuste o número de sublinhados iniciais. Para uma explicação linha a linha dessas opções, veja o guia do Telegraf MQTT consumer.
Passo 4: provisione o data source do Grafana
O provisionamento cria o data source do InfluxDB na inicialização, então ninguém precisa clicar pela interface. O Grafana também expande variáveis de ambiente nos arquivos de provisionamento.
# 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}
O uid fixo permite que o dashboard referencie esse data source de forma confiável.
Passo 5: provisione um dashboard pronto
Primeiro diga ao Grafana onde ficam os dashboards:
# grafana/provisioning/dashboards/dashboards.yml
apiVersion: 1
providers:
- name: mqtt
folder: MQTT
type: file
options:
path: /var/lib/grafana/dashboards
Depois adicione o dashboard em si. Ele tem uma série temporal de temperatura por dispositivo e um painel stat com o número de dispositivos que estão reportando.
{
"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()"
}
]
}
]
}
Se você mudou o nome do bucket no .env, altere também "sensors" nas duas consultas. Você também pode importar esse JSON em Dashboards, depois New, depois Import, em qualquer instância existente do Grafana.
Passo 6: suba a stack e envie dados
cd tig-mqtt
docker compose up -d
docker compose ps
docker compose logs -f telegraf
Agora publique dados. A fonte contínua mais rápida é o nosso simulador de dispositivos MQTT em Python; rode-o com --prefix connectmq/demo/a1b2c3 para que ele corresponda ao MQTT_TOPIC_PREFIX. Uma única mensagem de teste também funciona:
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}"
Abra http://localhost:3000, entre como admin com a GRAFANA_PASSWORD e abra o dashboard MQTT Sensors na pasta MQTT.
Verifique cada camada em ordem
Quando o dashboard continua vazio, resista à vontade de mudar várias coisas ao mesmo tempo. Percorra o pipeline e confirme cada camada antes de passar para a próxima:
- Broker. Execute
mosquitto_sub -h broker.connectmq.com -p 1883 -i check-a1b2c3 -t "connectmq/demo/a1b2c3/#" -v. Se nada aparecer, o problema está no publicador, não na stack. - Conexão do Telegraf.
docker compose logs telegrafdeve mostrar o plugin se conectando sem erros. Falhas de autenticação e erros de interpretação do topic aparecem aqui. - Interpretação no Telegraf. Adicione temporariamente um bloco
[[outputs.file]]comfiles = ["stdout"]e reinicie o Telegraf. As métricas interpretadas passam a aparecer nos logs em line protocol, o que prova que o JSON e o mapeamento de topics estão corretos. - InfluxDB. Execute
docker compose exec influxdb influx query 'from(bucket: "sensors") |> range(start: -5m) |> limit(n: 3)'. A CLI dentro do contêiner já vem configurada pela inicialização. - Grafana. Abra a página do data source e clique em Save and test; depois confira se o intervalo de tempo do dashboard cobre o período em que os dados foram gravados.
Na prática, a maioria dos problemas é encontrada no passo 1 ou no passo 3: um prefixo de topic que difere por um caractere, ou um payload que não é o JSON que a configuração espera.
Armadilhas da primeira execução
| Problema | Causa | Solução |
|---|---|---|
Token do .env rejeitado |
As variáveis de inicialização do InfluxDB só valem para um volume vazio | docker compose down -v para resetar, ou crie um novo token na interface |
| Telegraf: connection refused em localhost:8086 | Hostname errado dentro dos contêineres | Use http://influxdb:8086 |
| O dashboard mostra "No data" | O prefixo de topic no .env difere do que é publicado |
Compare com mosquitto_sub -t "connectmq/demo/a1b2c3/#" -v |
| Telegraf: erro de interpretação do topic | A profundidade do prefixo mudou, mas o padrão de tags não |
Faça o número de segmentos _ corresponder aos níveis do topic |
| Erro no data source do Grafana | Token ou org incompatíveis | Verifique a página do data source; os valores vêm do .env |
A stack funciona, mas os dados somem após down -v |
Volumes excluídos | Use docker compose down sem -v |
Migrando para um broker privado
Para equipamentos reais, como os sensores de uma planta em Campinas, só o .env muda. Aponte a stack para um broker MQTT gerenciado como a 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
O certificado é emitido pela Let's Encrypt, então o Telegraf confia nele sem configurações extras de TLS. Execute docker compose up -d de novo para recriar o contêiner do Telegraf com os novos valores. Coloque também o Grafana atrás de um proxy reverso com HTTPS antes de expô-lo além da sua máquina, e faça backup do volume influxdb-data.
Com o dashboard pronto, adicione alertas do Grafana para dados de sensores IoT sobre as mesmas consultas. Para escolhas de cliente mais amplas do lado dos dispositivos, veja o guia de bibliotecas de cliente MQTT; a documentação do Docker Compose cobre health checks e arquivos de ambiente em detalhes.
Comece com a ConnectMQ
Use o servidor MQTT público para subir a stack hoje mesmo com dados simulados; ele serve para testes, não para dados de produção. Para produção, a ConnectMQ oferece um broker MQTT gerenciado com TLS, MQTT 5 e um portal onde você acompanha os topics ao vivo antes mesmo de o Telegraf vê-los. Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito, e cole as credenciais no .env. Se estiver avaliando opções de hospedagem, leia nosso guia sobre broker MQTT na nuvem.
Perguntas frequentes
Posso rodar o broker MQTT dentro do mesmo arquivo Docker Compose?
Pode, mas um broker MQTT gerenciado e compartilhado costuma ser mais simples de operar e permite que outros consumidores usem os mesmos dados. Mantê-lo fora do Compose também significa que reiniciar a stack nunca interrompe os seus dispositivos.
Esta configuração de stack TIG com Docker Compose funciona com o InfluxDB 3?
Não sem alterações. O InfluxDB 3 usa outra imagem, outro procedimento de configuração e outras linguagens de consulta, então as variáveis de inicialização e as consultas Flux deste guia se aplicam ao InfluxDB 2.7.
Como adiciono mais dashboards?
Coloque arquivos JSON de dashboard adicionais em grafana/dashboards. O Grafana os carrega automaticamente pelo file provider.
Quanto espaço em disco os dados vão ocupar?
Depende do número de séries e da taxa de mensagens. A retenção de 30 dias do bucket mantém o crescimento sob controle; reduza-a ou faça downsampling dos dados mais antigos se o disco estiver apertado.



