Observabilidade em Microserviços Python no Kubernetes (Kind) com OpenTelemetry, Grafana, Tempo e Loki
Projeto de Observabilidade em Python(SRE/Observability) para demonstrar:
- Tracing distribuído (OpenTelemetry) com propagação entre serviços
- Logs no Loki com
trace_id real (32-hex) para correlação com traces no Tempo
- Grafana como “single pane of glass” (logs ↔ traces)
- Deploy via Helm e opção GitOps via ArgoCD
Componentes
- Serviços
catalog: produtos
cart: carrinho
order: pedidos/orquestração
- Observabilidade
- Tempo (traces), Loki (logs), Promtail (scrape/ship), Grafana (dashboards)
- Kubernetes
- Cluster local com Kind (foco em reproduzibilidade)
- Charts Helm em
./charts
Dashboards
- Observabilidade – Logs e Traces por Serviço: visão geral com filtros
namespace, app, trace_id
- Incidente – Erros, Logs e Traces: foco em incident response (erros 5xx + drill down)
Setup manual (Kind + Helm)
Pré-requisitos
docker, kind, kubectl, helm
Criar cluster e namespaces
kind create cluster --name virtual-store
kubectl create namespace virtual-store
kubectl create namespace observability
Instalar observabilidade (Tempo/Loki/Promtail/Grafana)
helm upgrade --install tempo ./charts/tempo --namespace observability
helm upgrade --install loki ./charts/loki --namespace observability
helm upgrade --install promtail ./charts/promtail --namespace observability
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
-n observability \
-f ./charts/kube-prometheus-stack/values.yaml
kubectl apply -n observability -f ./charts/kube-prometheus-stack/dashboards
Instalar banco (PostgreSQL)
Este banco é usado para persistir pedidos e registrar dependências entre serviços (ex: order-service -> cart-service/catalog-service) junto com trace_id e latência.
helm upgrade --install postgres ./charts/postgres -n virtual-store
Build e deploy dos serviços
- Build local das imagens (a partir de
./services):
docker build -t catalog:local -f ./services/catalog/Dockerfile ./services
docker build -t cart:local -f ./services/cart/Dockerfile ./services
docker build -t order:local -f ./services/order/Dockerfile ./services
- Carregar imagens no Kind:
kind load docker-image catalog:local --name virtual-store
kind load docker-image cart:local --name virtual-store
kind load docker-image order:local --name virtual-store
- Instalar os charts (ajuste a tag/repo conforme necessário):
helm upgrade --install catalog ./charts/catalog -n virtual-store \
--set image.repository=catalog --set image.tag=local
helm upgrade --install cart ./charts/cart -n virtual-store \
--set image.repository=cart --set image.tag=local
helm upgrade --install order ./charts/order -n virtual-store \
--set image.repository=order --set image.tag=local
Acessar Grafana
kubectl -n observability port-forward svc/kube-prometheus-stack-grafana 3000:80
URL: http://localhost:3000
Senha (admin):
kubectl get secret -n observability kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d
Gerar tráfego (para ver logs/traces)
- Port-forward do
order:
kubectl -n virtual-store port-forward svc/order 5002:5002
- Em outro terminal, gere requisições:
for i in $(seq 1 80); do
curl -s -X POST http://localhost:5002/orders \
-H 'content-type: application/json' \
-d '{"user_id":"u1"}' >/dev/null
sleep 0.05
done
Opcional (para enriquecer o cenário):
# adicionar produtos no catalog
kubectl -n virtual-store port-forward svc/catalog 5000:5000
curl -s -X POST http://localhost:5000/products -H 'content-type: application/json' -d '{"id":"p1","name":"Produto 1"}'
# adicionar item no carrinho
kubectl -n virtual-store port-forward svc/cart 5001:5001
curl -s -X POST http://localhost:5001/cart/u1 -H 'content-type: application/json' -d '{"id":"p1","qty":1}'
CI/CD (GitOps)
CI (quality gate)
- Workflow:
.github/workflows/ci.yaml
- Quando roda: em push e em pull request
- O que faz: para cada chart da lista (
cart, catalog, order, loki, promtail, tempo, postgres) executa:
helm lint (pega erros de chart/values)
helm template (garante que o chart renderiza)
Objetivo: falhar rápido quando um chart quebra, sem precisar de cluster.
CD GitOps (build + publish + bump)
- Workflow:
.github/workflows/cd-gitops.yaml
- Quando roda: push na
main quando muda:
services/** (código/Dockerfiles dos serviços)
.github/workflows/cd-gitops.yaml (o próprio pipeline)
O CD faz 3 coisas em sequência:
- Build e push das imagens no GHCR usando
docker buildx bake definido em services/docker-bake.hcl
- Atualiza
charts/*/values.yaml com image.repository e image.tag = <SHA do commit>
- Commit/push dessas mudanças (
chore(gitops): deploy <sha>) para o ArgoCD sincronizar
Por que não vira loop infinito?
- O CD não roda quando muda
charts/**.
- Então o commit automático de “bump” não re-dispara o CD.
GitOps com ArgoCD
Os manifests de ArgoCD estão em ./argocd (app-of-apps + Applications por componente).
Docs SRE
docs-sre/HANDBOOK.md
docs-sre/PLAYBOOK.md
docs-sre/RUNBOOK.md
Troubleshooting
- Veja
PROBLEMAS_ENCONTRADOS.md para histórico de problemas e correções.