Tutoriais de IoT

Stack TIG com Docker Compose para Dados MQTT

Uma configuração docker-compose completa para Telegraf, InfluxDB 2 e Grafana que assina um broker MQTT, armazena dados de sensores e já abre com data source e dashboard provisionados, além das armadilhas que quebram as primeiras execuções.

Diagrama da stack TIG com Docker Compose, com o Telegraf lendo topics MQTT, o InfluxDB armazenando métricas e dashboards do Grafana
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

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:

  1. 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.
  2. Conexão do Telegraf. docker compose logs telegraf deve mostrar o plugin se conectando sem erros. Falhas de autenticação e erros de interpretação do topic aparecem aqui.
  3. Interpretação no Telegraf. Adicione temporariamente um bloco [[outputs.file]] com files = ["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.
  4. 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.
  5. 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.

Artigos relacionados

Melhores Ferramentas CLI MQTT para Testes, Scripts e Depuração

Uma comparação prática entre mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, a CLI do MQTT.js, curl e mqttui, com o mesmo teste rodando no broker.connectmq.com, para você escolher a ferramenta certa para scripts e depuração.

9 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.