502 en Heimdall (authentik evictado por drenajes fallidos de kured) — 2026-09-24¶
Errores 502 intermitentes en
heimdall.local.gorkarevilla.com. No son de Heimdall: el backendforwardAuth(authentik) queda caído durante los drenajes fallidos de kured.
Estado¶
| Campo | Valor |
|---|---|
| Primera aparición | 2026-09-12 (primeros 502 de Uptime Kuma) |
| Estado | Resuelto |
| Resuelto | 2026-09-24 (reinicio controlado de kobe con switchover CNPG previo) |
| Severidad | Media |
| Servicios afectados | Heimdall, Authentik, Kured (drenaje de nodos) |
Síntomas¶
- 502 intermitentes en Heimdall (Uptime Kuma), recuperando en 1–111 min.
- Ventanas del 24-sep: 06:17, 06:34, 07:01, 08:17, 10:00, 11:06, 13:02, 14:33.
- También hubo 502 numerosos el 12-sep y el 13-sep.
Cronología (2026-09-24, hora local CEST)¶
| Hora | Evento | Evidencia |
|---|---|---|
| ~05:56–06:06 | kured detecta reboot-required y drena kobe; el drain falla (global timeout 10m) al no poder evictar authentik-db-1, vaultwarden-db-1 e instance-manager. Uncordonea. |
kubectl logs kured-8mppw |
| 06:10–06:25 | Se instala kernel 6.8.0-142 (unattended-upgrades) en los 3 nodos → sentinels /var/run/reboot-required. |
ls /var/run/reboot-required |
| 06:17–08:17 | 502 intermitentes en Heimdall (ventana de actuación de kured, 06:00–08:00). | Uptime Kuma |
| ~13:51 | authentik-server recreado en kobe (junto con coredns y metrics-server). |
kubectl get pods |
Causa raíz¶
Heimdall (ruta interna) va detrás del middleware authentik-forwardauth:
forwardAuth:
address: http://authentik-server.authentik.svc.cluster.local:80/outpost.goauthentik.io/auth/traefik
Cuando authentik-server está caído o reiniciando, Traefik devuelve 502. La
evidencia de que no es Heimdall: su pod lleva 11 días sin reinicios.
authentik-server se cae porque es evictado (terminación Completed /
exit 0 = SIGTERM de drenaje, no crash ni OOM; memoria 642–691 MB vs límite
2 Gi). El detonante de la mañana es kured:
05:56:17 Reboot required → Draining node kobe
06:06:19 Error draining kobe: [evict "authentik-db-1" ... "vaultwarden-db-1"
... "instance-manager-…": global timeout reached: 10m0s]
06:06:19 Unable to cordon or drain kobe … will release lock and retry …
06:06:19 Uncordoning node kobe
El drain falla porque 3 pods están protegidos por PodDisruptionBudget
(PDB) y no se pueden evictar (la evicción choca con el PDB → el API responde
429 Too Many Requests → kured reintenta en bucle hasta el global timeout
de 10 min):
| Pod | Namespace | PDB que lo bloquea |
|---|---|---|
authentik-db-1 (primario CNPG) |
authentik | authentik-db-primary minAvailable:1 |
vaultwarden-db-1 (primario CNPG) |
vaultwarden | vaultwarden-db-primary minAvailable:1 |
instance-manager-* |
longhorn-system | PDB por nodo minAvailable:1 |
El switchover automático de CNPG ("switchover ahead of drain", disparado por
el taint node.kubernetes.io/unschedulable del cordon) no se producía: el
PDB del primario bloquea la evicción antes de que CNPG pueda promocionar la
réplica. Durante los 10 min de reintentos, kured sí evicta a
authentik-server (Deployment sin PDB) → ventanas de 502. kured libera el
lock, no reinicia, y reintenta cada mañana.
Lo que se descartó¶
| Hipótesis | Resultado |
|---|---|
| Heimdall caído | No: pod 0 reinicios, 11 días |
| OOM de authentik | No: 642–691 MB vs límite 2 Gi (fix 9323afa ok) |
| Rollout de authentik | No: mismo ReplicaSet 15 días (evicciones, no deploy) |
Resolución / Plan de acción¶
Resuelto (24-sep, ~21:00 CEST) con un reinicio controlado de kobe:
- Switchover CNPG previo:
kubectl cnpg promotedeauthentik-db-2yvaultwarden-db-2(réplicas enkyrie) → los primarios dejankobe. - Cordon + drain de
kobe(con--ignore-daemonsets --delete-emptydir-data). Con los primarios ya fuera, el drain completa: los standbys CNPG evictan limpio y elinstance-managerde Longhorn acaba evictándose tras evacuar sus réplicas. - Reboot de
kobe(kernel6.8.0-139→6.8.0-142), sentinel/var/run/reboot-requireddesaparece. - Uncordon y verificación: cluster
Ready, ambos clusters CNPG enCluster in healthy state, volúmenes Longhorn reconstruidos (healthy).
Con los 3 nodos ya en 6.8.0-142 y sin sentinel, kured no tiene nada que
reiniciar → se acaban los 502 recurrentes de cada mañana.
Fix permanente (aplicado): el drenaje de kured no puede coordinar con CNPG
porque kured no añade el taint node.kubernetes.io/unschedulable al hacer
cordon (solo spec.unschedulable); CNPG detecta el drenaje por taint
(DRAIN_TAINTS, función isNodeUnschedulableOrBeingDrained), así que nunca
hacía switchover y su PDB bloqueaba el drain. Se resuelve con:
- [x]
blockingPodSelector: [cnpg.io/instanceRole=primary]en kured → kured se salta los nodos con primario CNPG (sin drain fallido, sin 502). Los nodos con primario se reinician a mano con switchover previo (docs/runbooks/reboot-nodo-cnpg.md). - [ ] (Opcional, si se quiere automatizar el switchover) evaluar un mecanismo
que añada el taint de drenaje antes de que kured drene, o un CronJob previo
a la ventana de kured que haga
kubectl cnpg promote. No necesario para el homelab.
Hipótesis pendientes¶
- ¿Por qué falla el drain? ~~¿PDB de Longhorn, o el
global timeoutde kured (10m) es demasiado corto?~~ Confirmado: son los PDB de los primarios CNPG y delinstance-managerde Longhorn los que bloquean la evicción (no el timeout). Elglobal timeoutes solo el síntoma final. - 502 fuera de la ventana de kured (10:00, 11:06, 13:02): ¿otro detonante?
Queda abierta; correlacionar con restarts de
authentik-servery eventos dekobefuera de la ventana de kured.