Skip to content

Argarm/rca-lab

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laboratorio local: k3d + ArgoCD (GitOps) + observabilidad LGTM

Entorno local y ligero sobre Docker, provisionado con Terraform, para probar despliegues GitOps con observabilidad. Terraform hace el bootstrap (cluster k3d, ArgoCD y las Application raíz) y a partir de ahí ArgoCD entrega las aplicaciones y el stack de observabilidad leyendo las definiciones de la carpeta gitops-repo/ de este mismo repo en GitHub, al que se conecta con una deploy key SSH de solo lectura (ver ADR-0007).

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).

Demo

Flujo de diagnóstico agéntico: una excepción en person-crud dispara la alerta y el agente genera el informe de causa raíz

Una petición inválida provoca un 500 en person-crud → Grafana dispara la alerta → el alert-enricher adjunta la traza de error de Tempo (con el commit exacto) → el ai-sre-agent clona el repo en ese commit y genera el informe de causa raíz (RCA) con un LLM local (Ollama qwen3:8b).

Arquitectura

Terraform (bootstrap)                      ArgoCD (GitOps, continuo)
  ├─ cluster k3d (k3s)                        ├─ root-apps      -> apps/workloads/:
  ├─ ArgoCD (Helm, ns platform)               │     nginx, podinfo, person-crud, telemetrygen
  ├─ deploy key SSH (repo GitHub)             └─ root-platform  -> apps/platform/:
  └─ 2 Applications raíz (App-of-Apps):             otel-collector, loki, tempo, mimir, grafana
       root-apps + root-platform
                                             (ArgoCD clona git@github.com:Argarm/rca-lab.git)

Telemetría:  apps --OTLP--> OTel Collector --> Loki (logs) / Tempo (trazas) / Mimir (métricas)
                                                        ^-- Grafana consulta los tres

Diagnóstico:  Grafana (alerta) --> alert-enricher (traza de Tempo + stacktrace)
                 --webhook--> ai-sre-agent (host): clona el repo en el commit de la traza
                              y genera un RCA con Ollama (qwen3:8b)   [proceso en el host]
  • Dos roots App-of-Apps: root-platform gestiona el stack de observabilidad (apps/platform/) y root-apps gestiona las aplicaciones (apps/workloads/). Separados para poder iterar sobre las apps sin arriesgar la plataforma, y viceversa. Terraform bootstrapea ambos.

  • Namespaces: platform (ArgoCD + observabilidad) y workloads (tus apps).

  • Fuente GitOps en GitHub: ArgoCD clona git@github.com:Argarm/rca-lab.git (repo privado) con una deploy key SSH de solo lectura y lee los manifiestos de gitops-repo/. El ciclo es GitOps real: editas → git commitgit push a GitHub → ArgoCD sincroniza. La clave privada vive fuera de git (terraform/.secrets/, gitignored). Ver ADR-0007.

Requisitos

  • Windows + Docker Desktop (backend Linux/WSL2) en marcha.
  • terraform y k3d (el script up.ps1 los instala con winget si faltan).
  • Ya presentes en este equipo: kubectl, helm, git.

Uso

# Arrancar todo
./scripts/up.ps1

# Destruir todo
./scripts/down.ps1

O directamente con Terraform:

cd terraform
terraform init
terraform apply -target="null_resource.k3d_cluster"   # fase 1: cluster (kubeconfig)
terraform apply                                        # fase 2: resto
terraform output

Por qué dos fases: los providers de Kubernetes/Helm necesitan el kubeconfig que k3d escribe al crear el cluster. Crear primero el cluster con -target evita fallos de conexión en el primer apply. En aplicaciones posteriores basta con terraform apply.

Acceso

Los Ingress usan Traefik (incluido en k3s) y *.localhost (resuelve a 127.0.0.1). Puerto host 8080.

Servicio URL Credenciales
ArgoCD http://argocd.localhost:8080 admin / ver comando abajo
Grafana http://grafana.localhost:8080 admin / admin
podinfo http://podinfo.localhost:8080
nginx http://nginx.localhost:8080

Password inicial de admin de ArgoCD:

$pw = kubectl -n platform get secret argocd-initial-admin-secret -o jsonpath='{.data.password}'
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($pw))

Alternativa por port-forward (si el Ingress diera problemas):

kubectl -n platform port-forward svc/argocd-server 8081:80   # http://localhost:8081
kubectl -n platform port-forward svc/grafana 3000:80         # http://localhost:3000

Probar el flujo GitOps

  1. Edita gitops-repo/workloads/podinfo/deployment.yaml y pon replicas: 2.
  2. Haz commit y push a GitHub:
    git commit -am "podinfo a 2 réplicas"; git push
  3. ArgoCD detecta el nuevo commit y sincroniza solo (poll ~3 min). Para forzarlo al momento:
    kubectl -n platform annotate app podinfo argocd.argoproj.io/refresh=hard --overwrite
    kubectl -n workloads get pods -l app=podinfo    # deberían aparecer 2

Desplegar tu propia aplicación

Para llevar una app local (con su Dockerfile) al cluster hay dos planos que no se mezclan: la imagen viaja por Docker, y el despliegue se declara en git para que ArgoCD lo entregue.

El código fuente de tus apps vive en apps-src/ (una subcarpeta por app, cada una con su Dockerfile). Ese código no lo lee ArgoCD: solo se construye en imagen y se importa al cluster con build.ps1. Los manifiestos de Kubernetes, en cambio, sí van en gitops-repo/ (es lo que ArgoCD lee de GitHub). apps-src/person-crud/ es un submódulo git (repo propio en GitHub).

1. Construir e importar la imagen (no hay registry: hay que meter la imagen en k3d a mano):

./scripts/build.ps1 0.1.0            # construye TODAS las apps de apps-src/ con ese tag e importa a k3d
./scripts/build.ps1 0.1.0 hello-api  # solo una app

Usa un tag fijo y súbelo en cada cambio (0.1.00.1.1…). Con imagePullPolicy: IfNotPresent, reutilizar el mismo tag no redespliega porque Kubernetes no detecta que la imagen cambió.

2. Declarar el despliegue en GitOps. Crea gitops-repo/workloads/<app>/ con deployment.yaml, service.yaml, ingress.yaml y kustomization.yaml (clona workloads/podinfo/ como plantilla). En el deployment, apunta a tu imagen y no la bajes de internet:

      containers:
        - name: <app>
          image: <app>:0.1.0
          imagePullPolicy: IfNotPresent   # usa la imagen importada en k3d
          ports:
            - name: http
              containerPort: <puerto-del-Dockerfile>

Añade la Application hija en gitops-repo/apps/workloads/app-<app>.yaml (clona apps/workloads/app-podinfo.yaml; root-apps la recoge sola por estar en apps/workloads/), con path: workloads/<app> y namespace: workloads. Si en cambio fuera un componente de plataforma, iría en apps/platform/ y lo gestionaría root-platform.

3. Publicar (commit + push a GitHub — es lo que ArgoCD lee):

git add -A; git commit -m "add <app>"; git push

ArgoCD sincroniza solo. La app queda en http://<app>.localhost:8080 (según el host del Ingress).

Bucle de actualización: cambia el código → ./scripts/build.ps1 0.1.1 → actualiza image: <app>:0.1.1 en el deployment → commit. ArgoCD redespliega.

Verificar la observabilidad

  • En Grafana, los 3 datasources (Mimir/Loki/Tempo) deben dar "OK" en su prueba.
  • En Explore verás trazas (Tempo), métricas (Mimir) y logs (Loki) que genera telemetrygen continuamente hacia el Collector.

Estructura

terraform/        Capa de aprovisionamiento (bootstrap)
k3d/              Definición del cluster k3d
argocd/           values.yaml del chart + los 2 roots (root-platform.yaml, root-apps.yaml)
gitops-repo/      Carpeta que consume ArgoCD (la lee de GitHub, no es un repo aparte)
  apps/
    platform/     Applications hijas de plataforma/observabilidad (las vigila root-platform)
    workloads/    Applications hijas de aplicaciones (las vigila root-apps)
  workloads/      Manifiestos de nginx, podinfo, person-crud, telemetrygen, alert-enricher
  observability/  Mimir monolítico (manifiestos)
apps-src/         Código + Dockerfile de tus apps de ejemplo (se construyen con build.ps1)
                  person-crud/ es un submódulo git; alert-enricher/ el enriquecedor de alertas
scripts/          up.ps1 / down.ps1 / build.ps1
docs/adr/         Decisiones de arquitectura (ADR) y pendientes para futuras iteraciones

Las decisiones de diseño y los problemas de raíz resueltos están documentados en docs/adr/ (dos roots, entrega de imágenes locales, instrumentación OpenTelemetry, webhook al agente SRE, y la migración del repo GitOps a GitHub), junto con los puntos pendientes.

¿Retomando el proyecto? Empieza por docs/ESTADO.md: resume qué hay hecho y los pasos exactos para volver a levantarlo (up.ps1 + build.ps1).

Notas y resolución de problemas

  • Versiones de charts: las Application de observabilidad (gitops-repo/apps/platform/obs-*.yaml) fijan versiones de chart (loki, tempo, grafana, opentelemetry-collector). Si una versión ya no existe o su esquema de values cambió, edita el targetRevision/values de ese fichero y haz commit.
  • host.k3d.internal (legado): terraform/coredns.tf aún provisiona un ConfigMap coredns-custom que resuelve host.k3d.internal al gateway de la red del cluster. Era necesario cuando ArgoCD clonaba del git-server publicado en el host; tras migrar a GitHub (ADR-0007) ArgoCD resuelve github.com por SSH y ya no lo necesita, y el enricher alcanza el host por host.docker.internal. Queda como recurso vestigial; candidato a eliminar (ver docs/adr/README.md).
  • Helm: no cached repo found en el apply: el provider helm de Terraform carga el índice de todos los repos de Helm registrados, y su caché vive en %TEMP%\helm (que Windows vacía). Si falta, el apply de ArgoCD revienta. up.ps1 ejecuta helm repo update antes del apply para regenerarlo; si lo lanzas a mano, corre helm repo update primero.
  • Primer arranque: descarga imágenes (k3s, ArgoCD, LGTM, podinfo); necesita internet la primera vez. Después queda en la caché de Docker.
  • Solo Windows: los local-exec usan PowerShell. Portable a bash cambiando el interpreter.

Flujo de diagnóstico agéntico (implementado)

Lo que antes era "ampliación futura" ya está montado: una alerta de Grafana dispara un análisis de causa raíz automático. Resumido:

  1. Alerta. Regla ErrorEnCualquierServicio en Grafana (obs-grafana.yaml): dispara un webhook cuando alguna traza marca status_code=STATUS_CODE_ERROR.
  2. Enriquecimiento. alert-enricher (workload) recibe el webhook, busca en Tempo la traza de error del servicio y extrae excepción + stacktrace + atributos del span (incluido vcs.repository.url.full y el commit vcs.ref.head.revision). Reenvía el cuerpo enriquecido por webhook.
  3. RCA con contexto de código. ai-sre-agent (proceso Node en el host, repo aparte) responde 202 al instante y en background clona el repositorio en el commit exacto de la traza y lanza un RCA agéntico contra un LLM local (Ollama qwen3:8b). Guarda un informe en reports/*.json.

Detalle y decisiones en ADR-0006. El aprendizaje clave: sin el código el LLM alucinaba infraestructura inexistente; dándole el fuente en el commit correcto, el RCA acierta el bug real. El receptor vive fuera del cluster (depende del Ollama del host).

Próximo paso (roadmap): que el agente no se quede en el diagnóstico y proponga el fix en un Pull Request (de "te digo qué se rompió" a "te dejo el arreglo listo para revisar"), con revisión humana y sin auto-merge. Ver ESTADO.md § Próximos pasos.

About

Autonomous SRE on-call agent: detect, RCA, and propose GitOps PR fixes

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors