Saltar a contenido

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 backend forwardAuth (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:

  1. Switchover CNPG previo: kubectl cnpg promote de authentik-db-2 y vaultwarden-db-2 (réplicas en kyrie) → los primarios dejan kobe.
  2. Cordon + drain de kobe (con --ignore-daemonsets --delete-emptydir-data). Con los primarios ya fuera, el drain completa: los standbys CNPG evictan limpio y el instance-manager de Longhorn acaba evictándose tras evacuar sus réplicas.
  3. Reboot de kobe (kernel 6.8.0-139 → 6.8.0-142), sentinel /var/run/reboot-required desaparece.
  4. Uncordon y verificación: cluster Ready, ambos clusters CNPG en Cluster 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

  1. ¿Por qué falla el drain? ~~¿PDB de Longhorn, o el global timeout de kured (10m) es demasiado corto?~~ Confirmado: son los PDB de los primarios CNPG y del instance-manager de Longhorn los que bloquean la evicción (no el timeout). El global timeout es solo el síntoma final.
  2. 502 fuera de la ventana de kured (10:00, 11:06, 13:02): ¿otro detonante? Queda abierta; correlacionar con restarts de authentik-server y eventos de kobe fuera de la ventana de kured.

Referencias