1. Introdução e arquitetura
Uma stack de observabilidade responde três perguntas: o que está acontecendo (métricas), por que (logs) e onde (traces). Neste guia montamos tudo com Docker Compose:
- Prometheus — coleta e armazena métricas
- Loki — agrega logs (estilo Prometheus)
- Grafana — visualização unificada
- OpenTelemetry Collector — recebe traces, métricas e logs das apps
2. Pré-requisitos
- Docker + Docker Compose 2.x
- ~4 GB RAM livres (8 GB mais confortável)
- Portas: 3000, 9090, 3100, 4317/4318
3. Estrutura e docker-compose
observabilidade/
├── docker-compose.yml
├── prometheus/prometheus.yml
├── loki/loki-config.yml
├── otel/otel-collector-config.yml
└── grafana/provisioning/datasources/datasources.yml
version: "3.8"
services:
prometheus:
image: prom/prometheus:v2.54.0
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--web.enable-lifecycle"
ports:
- "9090:9090"
restart: unless-stopped
loki:
image: grafana/loki:3.0.0
volumes:
- ./loki/loki-config.yml:/etc/loki/local-config.yaml
- loki_data:/loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
restart: unless-stopped
grafana:
image: grafana/grafana:11.1.0
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin123
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
ports:
- "3000:3000"
depends_on:
- prometheus
- loki
restart: unless-stopped
otel-collector:
image: otel/opentelemetry-collector-contrib:0.105.0
volumes:
- ./otel/otel-collector-config.yml:/etc/otelcol/config.yaml
ports:
- "4317:4317"
- "4318:4318"
depends_on:
- prometheus
- loki
restart: unless-stopped
volumes:
prometheus_data:
loki_data:
grafana_data:
4. Prometheus
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
- job_name: "otel-collector"
static_configs:
- targets: ["otel-collector:8888"]
5. Loki
auth_enabled: false
server:
http_listen_port: 3100
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
6. Grafana + datasources
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
- name: Loki
type: loki
access: proxy
url: http://loki:3100
$ docker compose up -d
Grafana → http://localhost:3000 (admin / admin123)
Prometheus → http://localhost:9090
warn · Altere a senha do Grafana imediatamente em qualquer ambiente exposto.
7. OpenTelemetry Collector
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
exporters:
prometheus:
endpoint: "0.0.0.0:8888"
loki:
endpoint: http://loki:3100/loki/api/v1/push
logging:
loglevel: info
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus, logging]
logs:
receivers: [otlp]
processors: [batch]
exporters: [loki, logging]
traces:
receivers: [otlp]
processors: [batch]
exporters: [logging]
8. Exporters
Adicione o node-exporter ao compose e o job correspondente no prometheus.yml para métricas de host. Instrumente apps com SDKs OTel apontando para localhost:4318 (HTTP) ou :4317 (gRPC).
9. Dashboards
- Grafana → Dashboards → Import
- Node Exporter oficial (ID 1860)
- Crie painéis LogQL no Loki para logs de containers
tip · Use labels consistentes (job, instance, service) para correlacionar métricas e logs.
10. Próximos passos
- Adicionar Tempo/Jaeger para traces
- Alertas no Grafana + Alertmanager
- Instrumentar aplicações reais
- Reverse proxy com TLS (Traefik/Nginx)
- Versionar configs no Git
Stack leve o bastante para homelab e sólida para dev/staging. Em produção, refine retenção, HA e segurança.
11. Configurações explicadas
docker-compose.yml
| Trecho | O que faz |
|---|
image: prom/prometheus:v2.54.0 | Imagem com a versão fixada, para o ambiente não mudar sozinho. |
./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml | Monta o arquivo de configuração do host dentro do container. |
prometheus_data:/prometheus | Volume nomeado: os dados sobrevivem à recriação do container. |
--config.file e --storage.tsdb.path | Indicam o arquivo de configuração e a pasta do banco de séries temporais. |
--web.enable-lifecycle | Permite recarregar a configuração com uma chamada HTTP, sem reiniciar. |
ports: "9090:9090" | Formato porta-do-host:porta-do-container. |
restart: unless-stopped | Reinicia o container após falhas ou reinício do host, a menos que você o pare. |
depends_on | Define a ordem de início. Ela não espera o serviço estar pronto. |
GF_SECURITY_ADMIN_USER e GF_SECURITY_ADMIN_PASSWORD | Usuário e senha iniciais do Grafana. |
GF_USERS_ALLOW_SIGN_UP=false | Impede que qualquer pessoa crie uma conta. |
| Serviço | Porta | Para que serve |
|---|
| Prometheus | 9090 | interface e API de métricas |
| Loki | 3100 | recebe e consulta logs |
| Grafana | 3000 | painéis e consultas |
| OTel Collector | 4317 e 4318 | recebe dados por OTLP (gRPC e HTTP) |
prometheus.yml, Loki e Grafana
| Configuração | O que faz |
|---|
scrape_interval: 15s | A cada 15 segundos o Prometheus coleta as métricas dos alvos. |
evaluation_interval: 15s | Frequência de avaliação das regras de alerta. |
job_name e static_configs: targets | Nome do grupo de coleta e a lista de endereços a consultar. |
auth_enabled: false (Loki) | Sem multi-tenant, adequado a um único ambiente. |
replication_factor: 1 e store: inmemory | Instância única, sem cluster. |
access: proxy (Grafana) | O Grafana faz a consulta ao servidor, em vez do navegador. |
url: http://prometheus:9090 | Usa o nome do serviço na rede do Compose. |
OpenTelemetry Collector
| Bloco | O que faz |
|---|
receivers: otlp | Recebe dados no formato OTLP, por gRPC (4317) ou HTTP (4318). |
processors: batch | Agrupa os dados antes de enviar, o que reduz o número de requisições. |
exporters | Destinos: prometheus para métricas, loki para logs e logging para depurar na saída do container. |
service: pipelines | Liga receptores, processadores e exportadores para cada tipo de sinal. Aqui os traces só vão para o logging, pois a stack não tem backend de traces. |
12. Como conferir se subiu
docker compose up -d
docker compose ps
curl -s http://localhost:9090/-/ready
curl -s http://localhost:3100/ready
docker compose logs -f otel-collector
| Comando | O que esperar |
|---|
docker compose ps | os quatro serviços em running |
curl .../9090/-/ready | a mensagem de que o Prometheus está pronto |
curl .../3100/ready | ready. O Loki pode levar alguns segundos após subir |
docker compose logs -f otel-collector | erros de configuração, se houver |
13. Erros comuns e como resolver
| Sintoma | Causa provável | Solução |
|---|
| O Collector falha com "address already in use" na porta 8888 | O exporter Prometheus usa a mesma porta das métricas internas do próprio Collector. | Mude o exporter para 0.0.0.0:8889 (como no artigo de OpenTelemetry) e o alvo do prometheus.yml para otel-collector:8889. |
Um alvo aparece como DOWN no Prometheus | Nome de serviço ou porta errados. | Abra Status → Targets e confira o erro exibido. |
Aviso "the attribute version is obsolete" | O Compose atual ignora o campo version. | Remova a linha version: "3.8". O restante continua igual. |
O exportador logging não é reconhecido | Versões novas do Collector o substituíram pelo debug. | Troque o nome do exportador ou mantenha a versão fixada da imagem. |
Alguém acessa o Grafana com admin123 | A senha padrão do exemplo ficou em uso. | Troque a senha e evite deixá-la no arquivo versionado. |