Entorno local sobre Docker, provisionado con Terraform, para probar despliegues de aplicaciones y
observabilidad. Terraform crea el cluster k3d, los namespaces y el stack LGTM; deploy.ps1 aplica
los manifiestos declarativos de las aplicaciones desde este mismo repositorio.
Sobre esa base corre un flujo de diagnóstico agéntico de incidentes: una alerta de Grafana se enriquece con la traza de error y se envía a un agente que genera un análisis de causa raíz (RCA) con un LLM local, leyendo el código fuente real (ADR-0006).
Una aplicación provoca un error
500→ Grafana dispara la alerta → elalert-enricheradjunta la traza de error de Tempo → elai-sre-agentgenera el informe de causa raíz con Ollama.
Terraform + Helm Kubernetes (k3d)
├─ cluster k3d (k3s) ├─ platform: Grafana, Loki, Tempo, Mimir, OTel Collector
├─ namespaces platform/workloads └─ workloads: nginx, podinfo, telemetrygen, alert-enricher
└─ charts de observabilidad
scripts/deploy.ps1
├─ kubectl apply -k gitops/observability/mimir
└─ kubectl apply -k gitops/workloads/<app>
Telemetría: apps --OTLP--> OTel Collector --> Loki / Tempo / Mimir
^-- Grafana consulta los tres
Diagnóstico: Grafana (alerta) --> alert-enricher --> ai-sre-agent (host)
- Terraform gestiona la infraestructura y los cuatro charts Helm de observabilidad.
- Los manifiestos Kubernetes de las aplicaciones viven en
gitops/y se aplican localmente conkubectl apply -k; siguen estando versionados y son reproducibles. build.ps1construye e importa las imágenes locales al cluster. No se usa ningún registry.alert-enricherreenvía el webhook al procesoai-sre-agentque corre en el host.
- Windows + Docker Desktop (backend Linux/WSL2) en marcha.
terraform,k3d,helm,kubectlygit.- Conexión a internet en el primer arranque para descargar providers, charts e imágenes.
up.ps1 instala k3d, Helm y Terraform con winget si faltan.
Desde la raíz del repositorio:
# Crear el cluster, namespaces y observabilidad, y aplicar los manifiestos locales
./scripts/up.ps1
# Construir/importar una imagen local
./scripts/build.ps1 0.1.2 alert-enricher
# Reaplicar Mimir y los workloads después de importar imágenes o editar manifiestos
./scripts/deploy.ps1
# Destruir el laboratorio
./scripts/down.ps1Para ejecutar Terraform directamente:
terraform -chdir=infrastructure/terraform init
terraform -chdir=infrastructure/terraform apply -target="null_resource.k3d_cluster"
terraform -chdir=infrastructure/terraform apply
./scripts/deploy.ps1El primer apply crea el cluster para que k3d escriba el kubeconfig. El segundo instala los charts
de observabilidad. deploy.ps1 aplica después Mimir y las aplicaciones.
Los Ingress usan Traefik, incluido en k3s, y el puerto host 8080.
| Servicio | URL | Credenciales |
|---|---|---|
| Grafana | http://grafana.localhost:8080 | admin / admin |
| podinfo | http://podinfo.localhost:8080 | — |
| nginx | http://nginx.localhost:8080 | — |
Si el DNS *.localhost no está disponible, prueba contra http://127.0.0.1:8080 enviando el
encabezado Host correspondiente.
Alternativa por port-forward:
kubectl -n platform port-forward svc/grafana 3000:80 # http://localhost:3000El proyecto separa el código de una aplicación de su definición Kubernetes:
apps/<app>/contiene el código y elDockerfilecuando la imagen se construye localmente.gitops/workloads/<app>/contiene los manifiestos Kustomize que se aplican al namespaceworkloads.
Una aplicación puede usar una imagen publicada —por ejemplo nginx o podinfo— o una imagen
local —como alert-enricher—. En ambos casos necesita su carpeta de manifiestos.
Crea gitops/workloads/<app>/kustomization.yaml y, como mínimo, un Deployment cuyo nombre sea
exactamente <app>:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: workloads
resources:
- deployment.yaml
- service.yaml
# - ingress.yaml # solo si debe exponerse fuera del clusterEl deployment.yaml debe contener metadata.name: <app> y la imagen que se quiere ejecutar.
Añade service.yaml para el acceso interno y ingress.yaml si la aplicación necesita una URL
desde el host. Puedes tomar gitops/workloads/podinfo/ como ejemplo.
scripts/deploy.ps1 descubre automáticamente las carpetas que contienen kustomization.yaml.
Aplica todos los workloads antes de esperar sus rollouts, para permitir dependencias entre ellos.
El Deployment debe llamarse igual que su carpeta.
Para una imagen publicada, pon su referencia en deployment.yaml y asegúrate de que el cluster
puede descargarla:
image: ghcr.io/empresa/<app>:1.0.0
imagePullPolicy: IfNotPresentPara una aplicación con código local, crea apps/<app>/Dockerfile y construye e importa la imagen
en el cluster k3d:
./scripts/build.ps1 -Tag 0.1.0 -App <app> -Cluster labEl script construye apps/<app>/, genera la imagen <app>:0.1.0 y la importa con k3d image import. El tag utilizado debe coincidir con el image: del Deployment:
image: <app>:0.1.0Si modificas el código, usa un tag nuevo (0.1.1, 0.1.2, etc.), actualiza el Deployment y
vuelve a importar la imagen. Esto es importante porque los deployments usan
imagePullPolicy: IfNotPresent.
Con Docker Desktop y el cluster levantados, ejecuta:
./scripts/deploy.ps1El script prepara PostgreSQL y NATS, reaplica Mimir y todas las aplicaciones descubiertas, y espera a que cada Deployment termine su rollout.
Comprueba el resultado con:
kubectl --context k3d-lab -n workloads get pods,svc,ingress
kubectl --context k3d-lab -n workloads rollout status deployment/<app>
kubectl --context k3d-lab -n workloads logs deployment/<app>Si tiene Ingress, prueba http://<host>.localhost:8080. Si solo tiene Service, utiliza un
port-forward:
kubectl --context k3d-lab -n workloads port-forward svc/<app> 8081:<puerto-del-service>Para un cluster ya preparado, ./scripts/up.ps1 crea o actualiza la infraestructura y termina
aplicando los workloads. Una imagen local debe estar importada antes de esperar el rollout de su
Deployment. Si el cluster se ha recreado y la aplicación usa una imagen local, ejecuta el flujo en
dos fases:
# Crear primero el cluster para que exista el destino de k3d image import
terraform -chdir=infrastructure/terraform init
terraform -chdir=infrastructure/terraform apply `
-target="null_resource.k3d_cluster" `
-auto-approve
# En Windows, corrige el endpoint si k3d ha escrito host.docker.internal y no conecta
$server = kubectl config view --context k3d-lab -o jsonpath='{.clusters[0].cluster.server}'
if ($server -match "host\.docker\.internal") {
kubectl config set-cluster k3d-lab --server=$server.Replace("host.docker.internal", "127.0.0.1")
}
# Construir e importar las imágenes locales
./scripts/build.ps1 -Tag 0.1.0 -App <app> -Cluster lab
# Instalar observabilidad y aplicar los workloads
terraform -chdir=infrastructure/terraform apply -auto-approve
./scripts/deploy.ps1El despliegue local no hace pruning automático. Antes de borrar la carpeta de una aplicación, elimina sus recursos del cluster:
kubectl --context k3d-lab delete -k gitops/workloads/<app> --ignore-not-foundDespués elimina gitops/workloads/<app>/ y apps/<app>/ si existe.
- En Grafana, los datasources Mimir, Loki y Tempo deben dar
OK. - En Explore verás trazas, métricas y logs generados por
telemetrygen. - La regla
ErrorEnCualquierServicioenvía las alertas alalert-enricher, que busca la traza correspondiente en Tempo.
infrastructure/terraform/ Cluster, namespaces y charts Helm de observabilidad
infrastructure/helm-values/ Valores de Grafana, Loki, Tempo y OTel Collector
infrastructure/k3d/ Definición del cluster k3d
gitops/workloads/ Manifiestos Kustomize de las aplicaciones
gitops/observability/mimir/ Manifiestos Kustomize de Mimir
apps/ Código + Dockerfile de las apps incluidas
scripts/ up.ps1 / down.ps1 / build.ps1 / deploy.ps1
docs/adr/ Decisiones de arquitectura y contexto histórico
Las decisiones de diseño y los problemas resueltos están documentados en
docs/adr/. Los ADRs que mencionan ArgoCD describen una etapa histórica del
proyecto y se conservan como registro de decisiones anteriores.
La evolución prevista de los microservicios de BlastMap está en
docs/ROADMAP-MICROSERVICIOS.md.
Los tres servicios de negocio están implementados en carpetas independientes de apps/:
carrito, pagos simulados y notificaciones por JetStream, con bases de datos propias y tests.
Consulta uso y contratos y escenarios de fallo.
El despliegue de estos servicios en k3d queda pendiente; para verificarlos sin tocar el cluster:
./scripts/test.ps1 -IncludeIncidents- Helm:
no cached repo found: ejecutahelm repo updatey vuelve a lanzarup.ps1. El script también actualiza los repositoriosgrafanayopen-telemetryantes de Terraform. - Endpoint del API de k3d en Windows: si el kubeconfig usa
host.docker.internaly el puerto publicado rechaza conexiones,up.ps1lo normaliza a127.0.0.1después de crear el cluster. - Imágenes locales:
k3d image importsolo afecta al cluster actual. Tras recrearlo hay que ejecutarbuild.ps1otra vez. - Solo Windows: los
local-execy scripts usan PowerShell.
- Grafana evalúa
ErrorEnCualquierServiciocuando una traza tienestatus_code=STATUS_CODE_ERROR. alert-enricherbusca la traza de error en Tempo, extrae excepción, stacktrace y atributos del span, y reenvía el cuerpo enriquecido.ai-sre-agent, proceso Node en el host, genera un RCA contra Ollama y guarda el informe enreports/*.json.
El receptor final se arranca aparte:
cd C:\Users\aaron\Documents\Repos\ai-sre-agent
$env:PORT = "3100"; node server.jsConsulta ADR-0006 para el detalle del flujo.
