Karpenter + EKS: Target Groups fantasma y cómo estabilizarlos sin downtime
Nota de campo sobre un patrón frecuente en EKS: ALBs manuales, IPs de nodo en Target Groups y Karpenter. Cómo TargetGroupBinding (AWS Load Balancer Controller) recupera estabilidad sin reconstruir el API Gateway.
Por el equipo de QSTools — notas de campo compostas a partir de trabajo en EKS. Detalles generalizados a propósito.
En setups multi-cuenta AWS con EKS + Karpenter, aparece un fallo recurrente después de una migración apurada EC2→EKS: cada rotación de nodos tira el tráfico. Casi nunca es “culpa de Karpenter”. El data path sigue clavando IPs de nodo estáticas en Target Groups clásicos detrás de un ALB legacy.
Resumen
| Señal | Causa raíz | Remedio |
|---|---|---|
| Caídas al reescalar / deploy | TG con IPs de nodo estáticas | TargetGroupBinding + targetType: ip |
| Muchos tickets de soporte | API Gateway → ALB legacy sin LBC | Mantener ALB/Gateway; automatizar el TG |
| Miedo a tocar prod | Sin ventana de mantenimiento | Transición por fases, casi 0s de corte |
| Deuda pendiente | Nodos EKS en subredes públicas | Más seguro cuando el TG ya no depende de IPs de nodo |
El patrón: crecimiento más rápido que la gobernanza de red
Los equipos suelen empezar bien—cuentas separadas, Terraform, plantillas EKS—y después la velocidad de producto deja atrás la capa de exposición:
- Servicios todavía frente a ALBs manuales (nacidos para EC2).
- Migración a EKS sin modernizar ese modelo ALB/TG.
- API Gateway (VPC Link) pegado a esos ALBs.
- Target Groups con IPs de nodos hardcodeadas.
- Karpenter entra por costo/escala… y recicla esos nodos.
Día a día: cada deploy o reescalado = targets perdidos (“nodos fantasma”). La remediación suele tener una restricción dura: sin downtime en caminos críticos.
Diagnóstico en una frase
Karpenter hacía su trabajo. El TG seguía apuntando a IPs que ya no existían.
Solución en tres fases (cero downtime como restricción)
Fase 1 — Desacople con TargetGroupBinding
Usá el CRD TargetGroupBinding del AWS Load Balancer Controller (LBC) para que el controlador gestione el TG existente, sin recrear ALBs ni reescribir rutas del API Gateway.
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
name: tgb-servicio-critico
namespace: produccion
spec:
serviceRef:
name: svc-servicio-critico
port: 8080
targetGroupARN: arn:aws:elasticloadbalancing:region:123456789012:targetgroup/tg-critico/abcdef123456
targetType: ip
(ARN de ejemplo; en prod usá el de tu TG real.)
Fase 2 — Puertos y health checks
Alineá puerto del Service y path de health check para que el LBC registre pods (targetType: ip). En el incidente que documentamos, la reconciliación fue en vivo con interrupción prácticamente nula.
Fase 3 — Gobernanza en Helm
Con prod estable, meté anotaciones del LBC en los Service de los charts para que los próximos deploys no vuelvan al modo manual:
metadata:
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
Antes vs después
| Situación inicial | Después del cambio |
|---|---|
| Pérdida de tráfico al rotar nodos | Registro dinámico de endpoints por el LBC |
| Tickets en cada deploy / scale | Deploys estables sin retocar TGs a mano |
| Mantenimiento manual de Target Groups | Targeting a IP de pod (targetType: ip) |
| Parálisis por miedo al downtime | Cambio transparente en producción |
| Mismo patrón frágil copiado entre cuentas | Patrón repetible de chart/TGB por cluster |
Qué enseña esto (y qué queda abierto)
- Autoscaling ≠ magia de red. Si el data path asume IPs de nodo, Karpenter va a “romper” lo que ya estaba frágil.
TargetGroupBindinges un puente excelente cuando no podés rediseñar API Gateway + ALB en una sola ventana.- Siguiente paso típico: migrar nodos EKS de subredes públicas a privadas—después de que los targets no dependan de IPs de nodo.
Si estás en este lío (EKS + ALB legacy + Karpenter), el orden importa: estabilizar el TG primero, estandarizar Helm después, subredes privadas cuando el tráfico ya no dependa de IPs de nodo.