Pular para o conteúdo principal

Aula de Laboratório — Primeiros passos com Docker (stack IoT)

Ferramentas: Docker · VS Code (extensão Container Tools) · Mosquitto · Node-RED · MQTT Explorer


1. Objetivos de aprendizagem​

Ao final desta aula, o aluno será capaz de:

  • Explicar a diferença entre imagem e container e o papel do docker compose.
  • Subir e gerenciar uma stack de vários serviços com um único arquivo.
  • Usar o VS Code (extensão Container Tools) para subir, inspecionar e depurar containers.
  • Entender portas, volumes e redes na prática.
  • Verificar o broker MQTT (Mosquitto) e o MQTT Explorer, e abrir o Node-RED.
Pontos de commit

Os cartões "Ponto de commit" marcam cada tarefa avaliada. Copie o comando do cartão e faça o commit com a mensagem sugerida. Algumas tarefas pedem uma evidência (a saída de um comando salva num arquivo) — isso também é avaliado.


2. Pré-requisitos e instalação​

  1. Docker instalado (Docker Desktop no Windows/macOS; Docker Engine no Linux).
  2. VS Code com a extensão Container Tools (por Microsoft): abra a aba de extensões e procure por container tools.

    A antiga extensão "Docker" foi substituída pela Container Tools (ms-azuretools.vscode-containers), que traz o Container Explorer, IntelliSense de docker-compose.yml e comandos de Compose.

  3. Confirme no terminal integrado do VS Code:
    docker --version
    docker compose version

3. Conceitos rápidos​

TermoO que é
ImagemUm "molde" somente-leitura com o app e suas dependências.
ContainerUma instância em execução de uma imagem.
DockerfileA "receita" para construir uma imagem.
docker composeOrquestra vários containers a partir de um docker-compose.yml.
Porta host:containerPublica uma porta do container na sua máquina.
VolumeGuarda dados fora do container (persistem após reiniciar).
Rede (network)Deixa os containers se acharem pelo nome do serviço.

4. A stack esp32-iot​

Três serviços trabalhando juntos:

ServiçoHostContainerPara quê
Mosquitto18831883Broker MQTT (o ESP32 conecta aqui)
Mosquitto90019001MQTT sobre WebSockets (navegador)
Node-RED18801880Editor de fluxos (lógica low-code)
MQTT Explorer18813000Ver e publicar mensagens MQTT
docker-compose.yml
name: esp32-iot

services:
mosquitto:
image: eclipse-mosquitto:latest
container_name: mosquitto
ports:
- "1883:1883" # MQTT
- "9001:9001" # WebSockets
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/log
networks:
- iot-network
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"

node-red:
build:
context: .
dockerfile: Dockerfile
container_name: node-red
environment:
- TZ=America/Sao_Paulo
ports:
- "1880:1880" # UI do Node-RED
volumes:
- node-red-data:/data
depends_on:
- mosquitto
networks:
- iot-network
restart: unless-stopped

mqtt-explorer:
image: ruseler/mqtt-explorer:local
container_name: mqtt-explorer
restart: unless-stopped
ports:
- "1881:3000"
environment:
MQTT_EXPLORER_SKIP_AUTH: "true"
networks:
- iot-network
volumes:
- ./mqtt-explorer/data:/app/data
depends_on:
- mosquitto

volumes:
node-red-data:

networks:
iot-network:
driver: bridge
Antes de subir: 3 ajustes na stack
  1. O Dockerfile faz COPY settings.js e COPY flows.json — esses arquivos precisam existir na pasta (mesmo mínimos), ou o build falha. Vamos criá-los na Parte 1.
  2. A imagem ruseler/mqtt-explorer:local pode não existir na sua máquina. Se o pull falhar, troque :local por :latest.
  3. O comentário original do Node-RED citava "1881", mas o mapeamento é 1880:1880 (host 1880). O MQTT Explorer é quem usa o 1881. Deixe assim (sem conflito) — ou veja o Desafio D1.

Parte 1 — Preparar o projeto no VS Code​

Abra a pasta do projeto no VS Code (File → Open Folder) e monte esta estrutura:

docker-iot-stack/
├── docker-compose.yml
├── Dockerfile
├── settings.js
├── flows.json
├── mosquitto/
│ ├── config/
│ ├── data/
│ └── log/
└── mqtt-explorer/
└── data/

Crie os dois arquivos que o Dockerfile copia (senão o build quebra):

flows.json
[]

Um array vazio: o Node-RED sobe sem fluxos (vamos criar depois).

Ponto de commit · T1 (8 pts) #

prepara a stack: docker-compose, Dockerfile, settings.js e flows.json

git add . && git commit -m "T1: prepara a stack: docker-compose, Dockerfile, settings.js e flows.json" && git push

Parte 2 — Configurar o broker (Mosquitto)​

Crie mosquitto/config/mosquitto.conf. Sem isso, o Mosquitto 2.x sobe fechado (recusa conexões externas e anônimas).

mosquitto/config/mosquitto.conf
listener 1883 0.0.0.0

allow_anonymous true

persistence true
persistence_location /mosquitto/data/

log_dest stdout
log_dest file /mosquitto/log/mosquitto.log

listener 9001
protocol websockets
Por que esses valores

listener 1883 0.0.0.0 faz o broker aceitar conexões de outras máquinas (o ESP32). allow_anonymous true dispensa usuário/senha — o padrão do Mosquitto 2.x é recusar.

Ponto de commit · T2 (8 pts) #

configura o broker com mosquitto.conf

git add . && git commit -m "T2: configura o broker com mosquitto.conf" && git push

Parte 3 — Subir a stack pelo VS Code​

Você pode subir de duas formas (use a que preferir):

  1. Clique com o botão direito no docker-compose.yml → Compose Up.
  2. Abra o Container Explorer (ícone da baleia/containers na barra lateral) e veja os três containers subindo: mosquitto, node-red, mqtt-explorer.

Registre a evidência: salve a saída de docker compose ps em evidencias/compose-ps.txt.

mkdir -p evidencias
docker compose ps > evidencias/compose-ps.txt

Você deve ver os três serviços com estado running/Up.

Ponto de commit · T3 (8 pts) #

sobe a stack e registra o docker compose ps

git add docker-compose.yml evidencias/compose-ps.txt && git commit -m "T3: sobe a stack e registra o docker compose ps" && git push

Parte 4 — Explorar e testar no VS Code​

Explorar: no Container Explorer, clique com o botão direito em um container para View Logs (ver o log em tempo real) ou Attach Shell (abrir um terminal dentro do container).

Testar o MQTT direto no broker, via attach shell no mosquitto (ou docker exec):

# terminal 1 — assinar tudo em elt85b/
docker exec -it mosquitto mosquitto_sub -t "elt85b/#" -v

# terminal 2 — publicar uma mensagem
docker exec -it mosquitto mosquitto_pub -t "elt85b/teste" -m "ola docker"

Abra também o MQTT Explorer em http://localhost:1881 e veja a mensagem aparecer na árvore de tópicos.

Registre a evidência do teste:

docker exec mosquitto mosquitto_sub -t "elt85b/#" -v -C 1 > evidencias/mqtt.txt &
docker exec mosquitto mosquitto_pub -t "elt85b/teste" -m "ola docker"
Ponto de commit · T4 (8 pts) #

testa o MQTT (publica e assina) e registra evidencia

git add evidencias/mqtt.txt && git commit -m "T4: testa o MQTT (publica e assina) e registra evidencia" && git push

Parte 5 — Primeiro fluxo no Node-RED​

  1. Abra http://localhost:1880 no navegador.
  2. Arraste um nó inject e um nó debug para a tela e ligue um ao outro.
  3. Clique em Deploy e depois no botão do inject — veja a mensagem no painel debug.
  4. Exporte o fluxo: menu (☰) → Export → Download e salve como flows.json na pasta do projeto (substituindo o vazio).
Fluxo vira arquivo

O flows.json é o seu fluxo em texto. Versioná-lo no Git permite avaliar e recriar o fluxo em qualquer máquina.

Ponto de commit · T5 (8 pts) #

cria um fluxo no Node-RED e exporta flows.json

git add flows.json && git commit -m "T5: cria um fluxo no Node-RED e exporta flows.json" && git push

6. Projeto integrador — Dashboard da telemetria​

Junta a stack ao mundo real: um fluxo que assina a telemetria publicada por um ESP32 (do lab de WiFi/MQTT) e mostra o valor.

  1. Adicione um nó mqtt in conectado ao broker mosquitto:1883 (dentro da rede Docker, o host é o nome do serviço: mosquitto), assinando elt85b/grupo-a/telemetria.
  2. Ligue-o a um nó debug e a um nó de dashboard (ex.: text ou chart do @flowfuse/node-red-dashboard).
  3. Deploy. Publique uma mensagem de teste no tópico (pelo MQTT Explorer) e veja aparecer.
  4. Exporte o fluxo para flows.json.
Host do broker no Node-RED

Como o Node-RED e o Mosquitto estão na mesma rede (iot-network), o Node-RED alcança o broker pelo nome mosquitto na porta 1883 — não use localhost aqui (dentro do container, localhost é o próprio Node-RED).

Ponto de commit · T6 (20 pts) #

projeto: fluxo Node-RED assinando a telemetria

git add flows.json && git commit -m "T6: projeto: fluxo Node-RED assinando a telemetria" && git push

7. Desafios​

Tente resolver sem olhar o gabarito. Faça o commit de cada desafio conforme concluir.

D1. O comentário original mapeava o Node-RED em 1881, que conflita com o MQTT Explorer. Mude o Node-RED para uma porta livre no host (ex.: 1882:1880) e explique por que 1881:1880 daria erro.

Ponto de commit · T7 (10 pts) #

desafio D1: ajusta portas sem conflito

git add docker-compose.yml && git commit -m "T7: desafio D1: ajusta portas sem conflito" && git push

D2. Garanta que as mensagens retidas e a fila do broker sobrevivam a um docker compose down + up. (Dica: o volume ./mosquitto/data e persistence true já ajudam — teste publicando com -r e reiniciando.)

Ponto de commit · T8 (10 pts) #

desafio D2: persiste dados do broker em volume

git add evidencias/persistencia.txt && git commit -m "T8: desafio D2: persiste dados do broker em volume" && git push

D3. No Node-RED, adicione um dashboard (gauge ou chart) que mostre o campo temp do JSON recebido. Exporte o fluxo.

Ponto de commit · T9 (10 pts) #

desafio D3: dashboard no Node-RED com o valor recebido

git add flows.json && git commit -m "T9: desafio D3: dashboard no Node-RED com o valor recebido" && git push

D4. Adicione um healthcheck do Mosquitto no docker-compose.yml (ex.: testar a porta 1883) para o Compose saber se o broker está saudável.

Ponto de commit · T10 (10 pts) #

desafio D4: healthcheck do mosquitto no compose

git add docker-compose.yml && git commit -m "T10: desafio D4: healthcheck do mosquitto no compose" && git push

8. Gabarito​

Spoiler

Só abra depois de tentar os desafios por conta própria.

Ver soluções

D1. 1881 já é o host do MQTT Explorer; duas publicações do mesmo host geram erro "port is already allocated". Use outra porta livre:

node-red:
ports:
- "1882:1880" # host 1882 -> container 1880

D2. Publique uma mensagem retida e reinicie:

docker exec mosquitto mosquitto_pub -t "elt85b/status" -m "online" -r
docker compose down && docker compose up -d
docker exec mosquitto mosquitto_sub -t "elt85b/status" -v -C 1 > evidencias/persistencia.txt

A mensagem retida reaparece porque persistence true grava em ./mosquitto/data (volume).

D3. Fluxo: mqtt in → json (converte texto em objeto) → change/function (extrai msg.payload.temp) → nó de gauge/chart do dashboard. Exporte para flows.json.

D4. Healthcheck no serviço mosquitto:

healthcheck:
test:
["CMD-SHELL", "mosquitto_sub -t '$$SYS/#' -C 1 -W 3 -h localhost || exit 1"]
interval: 30s
timeout: 5s
retries: 3

9. Comandos úteis (cola)​

docker compose up -d --build # sobe (rebuild do Node-RED)
docker compose ps # estado dos servicos
docker compose logs -f node-red # acompanha o log de um servico
docker compose restart mosquitto # reinicia so o broker
docker compose down # derruba (mantem volumes)
docker compose down -v # derruba e apaga volumes nomeados

10. Checklist de encerramento​

  • Instalei o Docker e a extensão Container Tools no VS Code.
  • Subi a stack (up -d --build) e vi os 3 serviços em running.
  • Testei o MQTT (publiquei e assinei) e vi no MQTT Explorer (localhost:1881).
  • Abri o Node-RED (localhost:1880) e criei um fluxo.
  • Entendi por que o Node-RED usa o host mosquitto (rede Docker) e não localhost.
  • Resolvi ao menos os desafios D1 a D4.
  • Fiz o commit de cada ponto marcado (T1 a T10).

Fim da aula.