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
-
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.
-
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.
-
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.
-
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.
-
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
DiskPressureoMemoryPressure. - 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
commonLabelsconenvironment: 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
-
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.
-
Alertas en Grafana
- Simular una condición de presión de disco llenando temporalmente
/var/lib/longhorny observar que la alerta se dispara en 5 min. - Verificar que el panel de “Node Pressure” muestra la condición
DiskPressure.
- Simular una condición de presión de disco llenando temporalmente
-
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.
- Modificar un recurso en Git (por ejemplo, cambiar
-
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.mden 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-schedulerpara distribuir los pods de forma equilibrada y evitar que un solo nodo se convierta en cuello de botella de almacenamiento.