109 lines
5.5 KiB
Markdown
109 lines
5.5 KiB
Markdown
# Notas para agentes que trabajan en este cluster
|
|
|
|
Este es el directorio de trabajo de **Hermes** (el agente de Telegram) y de
|
|
cualquier sesión de Claude Code sobre el homelab. Aquí van solo las cosas que
|
|
**engañan al mirarlas**: lo que parece una avería y no lo es, y lo que parece
|
|
inofensivo y no lo es. Lo demás está en el skill `k8s-infra`.
|
|
|
|
## n8n: las ejecuciones «running» que nunca terminan NO están colgadas
|
|
|
|
Desde el **2026-07-30** el deployment lleva `EXECUTIONS_DATA_SAVE_ON_SUCCESS=none`.
|
|
Cuando un workflow sale **bien**, n8n crea igualmente la fila en
|
|
`execution_entity`, le pone `deletedAt` al instante y **no actualiza el estado**,
|
|
porque la va a tirar. El barrido duro se las lleva cada ~15 min.
|
|
|
|
O sea que `SELECT ... FROM execution_entity` enseña filas con
|
|
`status='running'` y `stoppedAt=NULL` que son **ejecuciones exitosas ya
|
|
borradas**. No hay nada que arreglar. Ya provocó un diagnóstico en falso el
|
|
mismo día que se puso.
|
|
|
|
Para saber si un workflow corre de verdad, mirar **`workflow_statistics`**:
|
|
|
|
```sql
|
|
SELECT name, count FROM workflow_statistics WHERE workflowId='<id>';
|
|
-- production_success sube en cada vuelta aunque la ejecución no se guarde
|
|
```
|
|
|
|
Sale también en `deletedAt IS NOT NULL`. Y ojo: `startedAt` y `deletedAt` no
|
|
llevan el mismo huso, así que restarlas no significa nada.
|
|
|
|
## n8n: lo que se ejecuta es la versión PUBLICADA, no el borrador
|
|
|
|
`workflow_entity.nodes` es el **borrador**. Producción usa la versión de
|
|
`workflow_history` apuntada por `workflow_entity.activeVersionId`. Editar
|
|
`nodes` a mano y reiniciar **no cambia nada y no da ningún error**. La API
|
|
pública (`PUT /api/v1/workflows/{id}`) sí publica; parcheando SQLite hay que
|
|
escribir en las dos tablas.
|
|
|
|
Diagnóstico rápido: comparar las dos columnas. Si difieren, lo que corre no es
|
|
lo que estás leyendo.
|
|
|
|
**Y aun escribiendo las dos, hay que REINICIAR el pod.** n8n carga los workflows
|
|
activos en memoria al arrancar; un `UPDATE` en SQLite no se los recarga, y la
|
|
ejecución siguiente sigue usando la versión vieja **sin dar ningún error**. Pasó
|
|
el 2026-07-31: la primera publicación coló solo porque ArgoCD reinició el pod
|
|
justo después por otro motivo, y la segunda se probó contra el código viejo
|
|
durante media hora. Regla: `kubectl -n n8n rollout restart deploy/n8n` y
|
|
comprobar que el `startTime` del pod es POSTERIOR a la escritura, antes de dar
|
|
por buena ninguna prueba.
|
|
|
|
## Antes de tocar una BD de un pod: desarmar ArgoCD
|
|
|
|
Casi todo está bajo Applications con `automated{selfHeal,prune}`. Un
|
|
`kubectl scale --replicas=0` para hacer un `VACUUM` se revierte solo a mitad.
|
|
|
|
```sh
|
|
kubectl -n argocd patch app <app> --type json \
|
|
-p '[{"op":"remove","path":"/spec/syncPolicy/automated"}]'
|
|
# ... trabajo ...
|
|
kubectl -n argocd patch app <app> --type merge \
|
|
-p '{"spec":{"syncPolicy":{"automated":{"prune":true,"selfHeal":true}}}}'
|
|
```
|
|
|
|
Rearmarlo al final levanta el pod y aplica la config nueva de una vez.
|
|
|
|
## ArgoCD: una Application de directorio se traga los `.json`
|
|
|
|
`path: n8n` incluye `*.yaml`, `*.yml` **y `*.json`** como manifiestos. Un JSON
|
|
que no sea un objeto de Kubernetes deja la app en `ComparisonError` («Object
|
|
'Kind' is missing»). Por eso `application-n8n.yaml` tiene
|
|
`directory.exclude: "workflow-*.json"`. Los `.md` no se parsean: este fichero es
|
|
seguro.
|
|
|
|
## El auto-reinicio de Uptime Kuma sí funciona (desde 2026-07-30) y va cerrado
|
|
|
|
Kuma cae → notificación «n8n Auto-Restart» → webhook público de n8n → PATCH del
|
|
`restartedAt`. Antes no reiniciaba nada (sin RBAC: 403), y sus «éxitos» eran el
|
|
aviso de FALLO enviándose bien.
|
|
|
|
- La SA es `n8n-restarter`. Desde el **2026-07-31** son **Roles por namespace
|
|
con `resourceNames`** sobre los 12 workloads exactos del `SERVICE_MAP` (ver
|
|
`n8n/rbac-restarter.yaml`), no un ClusterRole abierto. Si añades un servicio
|
|
al mapa, **hay que añadirlo también ahí** o dará 403 — deliberado: el mapa y
|
|
el permiso se mueven juntos.
|
|
Motivo: esa SA va montada en el **pod entero** de n8n y los nodos Code leen el
|
|
token de `/var/run/secrets/…`, así que cualquier workflow con un nodo Code
|
|
hereda lo que se conceda aquí. El límite no es el mapa, es el RBAC.
|
|
- La clave del mapa es el **nombre exacto del monitor en Kuma**. Renombrarlo
|
|
allí lo desconecta en silencio.
|
|
- El webhook exige la cabecera `X-Kuma-Token` (secret `n8n-kuma-webhook`, fuera
|
|
de git) y desde el **2026-07-31 falla en CERRADO**: el `env` ya no lleva
|
|
`optional`, así que sin secreto el pod no arranca, y la puerta lanza error si
|
|
la variable falta. Antes se saltaba la comprobación «para no quedarte sin
|
|
avisos», y ese argumento era falso: el aviso de caída lo manda Kuma por su
|
|
notificación 1, directa, no por este webhook.
|
|
- Para apps bajo ArgoCD, el `restartedAt` se **revierte** tras el reinicio. El
|
|
pod sí se reinicia; la anotación no queda. No es un fallo. Por eso el éxito se
|
|
comprueba con `observedGeneration >= la generation que devolvió el PATCH`, y
|
|
con `>=` y no con `==`: la reversión vuelve a subir la generation.
|
|
- **Cómo saber por qué rama fue una ejecución** cuando `SAVE_ON_SUCCESS=none` ya
|
|
la ha vaciado: por la duración. `deletedAt - startedAt` (con el offset fijo de
|
|
1 h) da ~0,02 s si la puerta rechazó, ~0,3 s si el PATCH falló y se fue por la
|
|
rama de fallo, y ~60 s si hizo el ciclo completo con su espera.
|
|
|
|
## Un workflow que termina en verde no dice que haya hecho su trabajo
|
|
|
|
Vale para n8n y para cualquier automatismo de aquí: comprobar el **efecto**
|
|
(que el `restartedAt` cambió, que el pod es nuevo, que el fichero está), no el
|
|
código de salida ni el contador de éxitos.
|