Problema

En un homelab basado en Kubernetes, la infraestructura pasa rápidamente de “contenedores corriendo” a “servicios críticos que deben estar disponibles”. El patrón recurrente es la falta de visibilidad operativa: pods que se reinician, volúmenes que entran en estado faulted, nodos que reciben presión de disco o memoria, y límites de recursos mal definidos que provocan OOMKilled. Cuando el monitoreo es solo una lista de dashboards sin alertas ni automatizaciones, cualquier anomalía se detecta demasiado tarde y la recuperación requiere intervención manual extensa.

Causa

  1. Recursos no alineados con la carga real

    • Requests y limits ausentes o demasiado bajos provocan CPU throttling y OOMKilled.
    • En clústers pequeños, la suma de requests supera la capacidad del nodo, disparando DiskPressure y MemoryPressure.
  2. Almacenamiento persistente mal dimensionado

    • Longhorn crea volúmenes sin políticas de expansión automática. Cuando el nodo se queda sin espacio, los PVC quedan Pending o los volúmenes pasan a Faulted.
  3. Configuración de GitOps incompleta

    • ArgoCD sincroniza los manifiestos, pero si los recursos de límite no están versionados, los cambios manuales se pierden y el estado deseado se desvía.
  4. Rutas de red y túneles externos

    • Cloudflare Tunnel o Tailscale pueden romperse por cambios de IP o expiración de tokens, dejando los servicios inaccesibles sin que el clúster lo reporte.
  5. Alertas ausentes o mal definidas

    • Grafana/Prometheus pueden mostrar métricas, pero sin reglas de alerta los eventos críticos quedan en los logs.

Solución

Una estrategia de observabilidad y ajuste continuo que combina:

1. Definir y versionar requests/limits

  • Añadir resources: a todos los Deployments y StatefulSets.
  • Utilizar Kustomize o Helm para que los valores vivan en el repositorio Git gestionado por ArgoCD.

2. Automatizar la detección de volúmenes problemáticos

  • Configurar un PrometheusRule que dispare alerta cuando longhorn_volume_status{status!="healthy"} sea verdadero.
  • Implementar un CronJob que intente expandir automáticamente los PVC que superen el 80 % de uso.

3. Centralizar métricas operativas en Grafana

  • Crear paneles que muestren:

    • Pods con restart count > 0 en los últimos 5 min.
    • Nodos con condiciones DiskPressure o MemoryPressure.
    • Uso de CPU/RAM por namespace y por deployment.
    • Espacio libre en cada nodo Longhorn.
  • Añadir enlaces directos desde Glance o cualquier homepage al dashboard de Grafana para acceso rápido.

4. Refinar la configuración de GitOps

  • Agrupar los manifiestos por capa (infra, storage, apps) y usar kustomization.yaml que incluya un commonLabels con environment: homelab.
  • Habilitar Prune en ArgoCD para que recursos huérfanos se eliminen automáticamente.

5. Fortalecer túneles y acceso remoto

  • Configurar Cloudflare Tunnel con service token de larga duración y rotarlo mediante un GitHub Action que actualice el secret en Kubernetes.
  • En Tailscale, usar ACLs que limiten el acceso a los rangos internos del homelab.

6. Implementar alertas proactivas

  • Regla de alerta para pods en CrashLoopBackOff > 3 veces en 10 min.
  • Regla para volúmenes Longhorn no saludables > 5 min.
  • Regla para nodos bajo presión de disco > 85 % de uso.

Cuándo aplicar esta solución

  • Síntomas: pods con reinicios frecuentes, nodos marcados con DiskPressure, PVC que no se crean, servicios inaccesibles tras cambios de red.
  • Entorno: cualquier clúster Kubernetes de tamaño pequeño‑mediano (1‑5 nodos) que use almacenamiento externo (Longhorn, Ceph, etc.) y dependa de túneles externos para acceso remoto.
  • Exclusiones: no es necesario en entornos donde los recursos están sobreaprovisionados y no se usan GitOps; tampoco aplica si el clúster está completamente gestionado por un proveedor cloud que ya ofrece alertas integradas.

Código

# Exportar pods con restart count > 0 en los últimos 5 minutos
kubectl get pods --all-namespaces \
  -o jsonpath='{range .items[?(@.status.containerStatuses[0].restartCount>0)]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'

# PrometheusRule para detectar volúmenes Longhorn no saludables
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: longhorn-health
  namespace: monitoring
spec:
  groups:
  - name: longhorn.rules
    rules:
    - alert: LonghornVolumeUnhealthy
      expr: longhorn_volume_status{status!="healthy"} == 1
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "Longhorn volume {{ $labels.volume }} is unhealthy"
        description: "The volume has been in a non‑healthy state for more than 5 minutes."
EOF

Verificación

  1. Reinicios de pods

    • Ejecutar el comando anterior y confirmar que la lista está vacía.
    • Si aparecen pods, revisar sus eventos (kubectl describe pod <name>) y ajustar límites.
  2. Alertas en Grafana

    • Simular una condición de presión de disco llenando temporalmente /var/lib/longhorn y observar que la alerta se dispara en 5 min.
    • Verificar que el panel de “Node Pressure” muestra la condición DiskPressure.
  3. Sincronización de ArgoCD

    • Modificar un recurso en Git (por ejemplo, cambiar resources.limits.cpu) y observar que ArgoCD marca el recurso como OutOfSync y lo vuelve a aplicar automáticamente.
  4. Túneles activos

    • Desde una máquina externa, intentar acceder a un servicio expuesto vía Cloudflare Tunnel.
    • Revocar el token en Cloudflare y confirmar que la alerta de “Tunnel disconnected” aparece en Prometheus.

Notas adicionales

  • Ajuste gradual: comienza con requests modestos y aumenta en función de los datos de uso real; sobreaprovisionar genera presión de recursos innecesaria.
  • Longhorn backups: habilita snapshots automáticos y verifica la restauración al menos una vez al mes; los volúmenes faulted a menudo se deben a corrupción que los snapshots pueden mitigar.
  • Documentación viva: mantén un archivo README.md en el repo GitOps que describa cómo añadir nuevos dashboards o reglas de alerta; evita que el conocimiento quede solo en la cabeza de un único administrador.
  • Seguridad de túneles: nunca expongas directamente la API de Kubernetes a Cloudflare; usa un Ingress interno y protege el endpoint con Cloudflare Access.
  • Escalado futuro: si planeas añadir más nodos, revisa la configuración de kube-scheduler para distribuir los pods de forma equilibrada y evitar que un solo nodo se convierta en cuello de botella de almacenamiento.