Dimensionar bien Kubernetes: el método que llevó un clúster de 7 a 4 nodos
La mayoría de los clústeres funcionan a base de suposiciones: requests copiados de un tutorial, node pools dimensionados para un lanzamiento de hace dos años y una factura cloud que nadie sabe explicar línea a línea. Cada mes pagas capacidad que está parada, y cada mes parece demasiado arriesgado tocarla. El right-sizing lo arregla sin cambiar nada que vean tus clientes. Este es exactamente el orden que sigo, con las consultas, los manifiestos y los comandos, y así un clúster de producción pasó de 7 a 4 nodos sin que ningún cliente lo notara.
Actualizado 11 min de lectura
1. Una línea base fiable
Antes de cambiar nada, hay que saber cuánto cuesta cada node pool y a quién pertenece. La FinOps Foundation lo llama la fase Inform, y el pilar de optimización de costes del Azure Well-Architected Framework empieza en el mismo sitio: no puedes optimizar lo que no puedes atribuir. En Azure, Cost Management con coste amortizado muestra el precio real por node pool, reservas incluidas. Etiqueta cada namespace con equipo y producto para poder repartir con justicia un clúster compartido y que cada euro tenga dueño.
Después compara tres cifras por namespace: lo que se pide, lo que realmente se usa y lo que ofrecen los nodos. Los requests son lo que el scheduler reserva y lo que pagas; el uso es lo que los contenedores consumen de verdad. En muchos clústeres los requests están muy por encima del uso real, y esa diferencia es exactamente lo que pagas. Apunta las tres cifras por namespace en una tabla sencilla. Será tu foto del antes y, más adelante, la prueba de que el cambio funcionó.
Consejo práctico
Usa el coste amortizado, no el real. Si no, una reserva comprada en enero hace que enero parezca caro y el resto del año barato.
2. Medir el p95 durante semanas reales
Saca CPU y memoria por contenedor de Prometheus durante dos a cuatro semanas y asegúrate de que esa ventana incluya un cierre de mes, una campaña o tu día de más carga. En AKS, el servicio gestionado de Prometheus de Azure Monitor recoge estas métricas sin que tengas que operar Prometheus. Dimensiona según el percentil 95, no la media: la media esconde justo los picos que provocan throttling y cierres por falta de memoria.
Trata CPU y memoria de forma distinta, porque Kubernetes también lo hace. La CPU es comprimible: un contenedor que quiere más de su parte simplemente va más lento. La memoria no: un contenedor que supera su límite de memoria se cierra y el pod se reinicia. Por eso en memoria mira también el máximo del working set, no solo el p95. Ejecuta las consultas por contenedor, exporta el resultado a una hoja y ordénalo por la diferencia entre request y p95. Las mayores diferencias, arriba, son por donde empiezas.
# p95 CPU (cores) per container over the last 14 days
quantile_over_time(0.95,
sum by (namespace, pod, container) (
rate(container_cpu_usage_seconds_total{container!="", container!="POD"}[5m])
)[14d:5m]
)
# Peak working-set memory (bytes) per container over the last 14 days
max_over_time(
container_memory_working_set_bytes{container!="", container!="POD"}[14d]
)Consejo práctico
No sumes la memoria de varios pods en rangos largos. Durante los despliegues se solapan pods viejos y nuevos, y la suma muestra un uso que nunca existió. Toma el máximo por contenedor.
3. Requests y límites a partir de los datos
Pon los requests de CPU en torno al p95 más un 10 a 20 % de margen, y los de memoria en el máximo observado más un colchón parecido. Mantén los límites de memoria iguales o cercanos al request, para que un pod con fugas no deje sin recursos a sus vecinos del mismo nodo. En CPU, muchos equipos quitan el límite del todo y confían en los requests para repartir de forma justa, lo que evita el throttling en servicios sensibles a la latencia; deja un límite de CPU donde necesites aislamiento estricto, por ejemplo para jobs por lotes junto a una API.
Despliega el cambio como cualquier otro cambio de código. Pon los nuevos valores en los values de Helm o en los overlays de Kustomize en Git y deja que tu herramienta GitOps, FluxCD o Argo CD, los aplique. Ve namespace a namespace, empezando por herramientas internas y staging, y vigila latencia, errores y reinicios durante un día antes de pasar al siguiente. Si algo no cuadra, la vuelta atrás es revertir un solo commit. Ese ritmo tranquilo y reversible es lo que hace que la gente confíe en el proceso.
# Helm values for one service, derived from 14-day p95 and max
resources:
requests:
cpu: 250m # p95 was ~210m
memory: 512Mi # max working set was ~430Mi
limits:
memory: 512Mi # equal to the request: no noisy neighbours
# no CPU limit: avoids throttling, requests keep sharing fairConsejo práctico
El Vertical Pod Autoscaler en modo recomendación (updateMode: Off) te da una segunda opinión por carga sin cambiar ni un solo pod.
Interactivo
¿Cuántos nodos necesitan de verdad tus requests?
Mueve los controles a tus cifras. Las requests deciden dónde caben los pods, así que unas requests infladas compran nodos que nadie usa.
Tamaño de nodo
5
nodos hoy
2
nodos tras el ajuste (200m)
60%
menos capacidad de nodos
Solo CPU, alrededor del 90 % de un nodo es asignable, mínimo 2 nodos por disponibilidad. Revisa la memoria igual antes de quitar un nodo.
Todas las calculadoras y checklists4. Elegir node pools que encajen con tus pods
Con requests honestos por fin ves la forma real de tu carga, y esa forma decide los tamaños de nodo. Demasiado pequeños y la sobrecarga por nodo de los pods del sistema, los DaemonSets y la reserva del kubelet se come buena parte de cada máquina. Demasiado grandes y un nodo medio vacío sale caro mientras el autoscaler no puede retirarlo. Una comprobación útil: ¿cuántos de tus pods típicos caben en un nodo y cuánto sobra? Las buenas prácticas de costes de AKS recomiendan el mismo ejercicio antes de elegir tamaños de VM.
Separa el trabajo según cómo se comporta. Un node pool de sistema pequeño para los componentes del clúster, un pool de usuario para producción y un node pool spot con un taint para el trabajo interrumpible, como jobs por lotes, runners de CI y entornos de desarrollo. La capacidad spot se puede retirar con poco aviso, así que solo deben acabar ahí las cargas que lo toleran. En AKS, el node auto-provisioning, basado en Karpenter, también puede elegir los tamaños de VM según lo que está pendiente.
5. Que el autoscaler haga la reducción
Con requests honestos y pools adecuados, el scheduler empaqueta mejor los pods y algunos nodos quedan casi vacíos. El cluster autoscaler lo detecta y los retira, siempre que los pods que contienen puedan moverse a otro sitio. Ese es el momento en que la factura baja de verdad, así que asegúrate de que el autoscaler pueda actuar: un mínimo y un máximo razonables por pool y nada que ate pods a nodos concretos sin motivo.
Vigila los bloqueos clásicos. Los pods con almacenamiento local, los pods sin controlador y los PodDisruptionBudgets demasiado estrictos pueden impedir que se retire un nodo. Los logs del autoscaler te dicen qué pod bloqueó qué nodo, y arreglar esos pocos casos suele valer más que otra ronda de ajuste de requests. Dale unos días y verás cómo el número de nodos se estabiliza en un nivel nuevo y más bajo.
Consejo práctico
Si el número de nodos no se mueve tras una semana, lee los eventos de scale-down del autoscaler antes de tocar nada más. Casi siempre nombran al único pod que estorba.
6. Retirar nodos con seguridad
A veces quieres ir más rápido y retirar nodos tú mismo, por ejemplo para pasar a un tamaño de VM nuevo. Antes de quitar nodos, comprueba que cada carga importante tenga al menos dos réplicas, un PodDisruptionBudget y una anti-afinidad razonable; si no, un drain puede tumbar un servicio. Después retira capacidad nodo a nodo: cordon, drain, vigilar errores y latencia, esperar, repetir.
Apunta el número mínimo de nodos anterior como vía de vuelta y baja el mínimo del autoscaler solo cuando el clúster lleve un tiempo funcionando tranquilo con menos nodos. En un clúster de producción así pasamos de 7 a 4 nodos y ningún cliente lo notó. El trabajo en sí no tuvo nada de espectacular, y de eso se trata: pasos pequeños, señales claras y una vuelta atrás a mano.
# Which workloads would block or break a drain?
kubectl get pdb -A
# One node at a time; check dashboards before the next one
kubectl cordon aks-userpool-12345678-vmss000003
kubectl drain aks-userpool-12345678-vmss000003 \
--ignore-daemonsets --delete-emptydir-data --timeout=10m
# After a calm week on fewer nodes, lower the autoscaler floor
az aks nodepool update -g rg-platform --cluster-name aks-prod -n userpool \
--update-cluster-autoscaler --min-count 2 --max-count 6Consejo práctico
Haz los drains en horario laboral con gente mirando los paneles, no a las 3 de la madrugada. Si algo inesperado se mueve, quieres ojos sobre las gráficas.
7. Comprometerse solo con el tamaño nuevo
Solo ahora compra reservas o savings plans, ajustados al clúster con el que acabaste, no al del principio. Los pilares de costes de los Well-Architected Frameworks de Azure y AWS dicen lo mismo con otras palabras: primero optimiza lo que usas y después el precio que pagas por ello. Cubre la base estable con compromisos de uno o tres años y deja los picos en pago por uso o spot.
Si ya tienes reservas para tamaños de VM que ya no usas, cámbialas o devuélvelas enseguida donde tu proveedor lo permita, en vez de dejarlas sin uso. Comprométete al final, no al principio: en el proyecto detrás de este método, las reservas fueron el último paso tras el dimensionado y la limpieza, y en conjunto el gasto en Azure bajó un 48 % en cinco semanas.
8. Mantenerlo pequeño: convertirlo en rutina
Los clústeres vuelven a crecer en silencio: un servicio nuevo copia requests generosos de uno antiguo, una prueba de carga deja un node pool escalado, un flag de depuración duplica los logs. La fase Operate de la FinOps Foundation trata justo de esto: convertir una limpieza puntual en un hábito. Envía un informe diario corto de costes al chat del equipo, fija presupuestos con alertas de previsión y añade una ResourceQuota por namespace para que los requests no se desvíen sin que nadie lo note.
Después pon la revisión del p95 en el calendario cada trimestre. Con las consultas ya hechas, lleva más o menos una hora y suele encontrar uno o dos servicios que han crecido desde la última vez. Los equipos que conservan el ahorro no son los de las herramientas más ingeniosas; son los que miran las cifras cada día y tratan el coste como la latencia o los errores, como una señal más de una plataforma sana.
Conclusión
El right-sizing es un ciclo, no un proyecto: medir el p95, cambiar un namespace, observar, dejar que los nodos sigan y comprometerse al final. En ese orden, el ahorro se queda.
Proyectos reales relacionados
Pruébalo tú mismo
Fuentes y guías oficiales
- Azure Well-Architected Framework: Cost Optimization pillar
- AKS: Best practices for cost optimization
- FinOps Foundation: FinOps Framework (Inform, Optimize, Operate)
- AWS Well-Architected: Cost Optimization pillar
- Kubernetes: Resource management for pods and containers
- Azure Monitor managed service for Prometheus
- AKS: Cluster autoscaler
- Kubernetes: Specifying a PodDisruptionBudget
Más artículos
- 3.025 pull requests en diez meses: un proceso de entrega con IA, desde dentro
- La Ley de IA de la UE para medianas empresas: qué te aplica y desde cuándo
- FinOps para el gasto en IA: tokens, caché, enrutado y presupuestos que aguantan
- Hacer visible una red de restaurantes en las respuestas de la IA: un proyecto GEO paso a paso
- Cómo está hecha esta web: estática donde se puede, en streaming donde hace falta
- Costes de Kubernetes en EKS y GKE: el mismo método, otras palancas
- Una landing zone para empresas medianas, en Terraform o Bicep: las piezas que importan
- El manual de migración de sistemas heredados: oleadas, ejecución en paralelo y recuentos y checksums idénticos
- Seguridad de MCP a fondo: dejar entrar a los asistentes de IA en tu producto sin abrir las puertas
- Monitorizar resultados de negocio: paneles en verde, caja vacía
- Agentes de IA por teléfono: la arquitectura y los tropiezos que ninguna demo enseña
- Pruebas de restauración: un backup que nunca has restaurado es solo una esperanza
- Respuestas de IA en streaming en Azure Static Web Apps: la cabecera que lo retenía todo
- Construir un asistente de IA para WhatsApp de principio a fin: lo que hace falta más allá de la demo
- Sistemas air-gapped: software crítico sin conexión a internet
- IA en producción en AWS: Amazon Bedrock y AgentCore en una configuración privada
- IA en producción con Microsoft Foundry: una configuración de referencia privada para agentes
- /goal, /loop o rutinas: deja de vigilar a tu agente de programación
- Los nuevos planes de Claude: Max, Ultra y lo que significan para los equipos
- OpenAI Codex a finales de 2026: goal mode, dots y cómo blindarlo
- ¿GitHub Copilot, Claude Code o Codex? Cómo elegiría para una empresa
- Fundamentos de GEO: cómo aparecer en las respuestas de la IA
- IA en producción en Google Cloud: de Vertex AI a Gemini Enterprise Agent Platform
- LLM locales en una red air-gapped: IA para tus datos más sensibles
- Quiero ejecutar un LLM local: ¿qué servidor compro?
- MiniMax M3: ¿un modelo puntero que puedes ejecutar tú mismo?
- Investigación de prompts a gran escala con un modelo abierto
- SEO y GEO juntos: una auditoría práctica en 6 pasos
- IA privada para datos sensibles: un LLM local que supera la revisión de seguridad
- Del prototipo con IA a producción: las ocho capas que añado, en este orden
