Saltar al contenido
Todos los artículos

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.

El ciclo de right-sizing en AKS: medir el p95, cambiar a través de Git, dejar que los nodos sigan, informar a diario y comprometerse al final.
Arquitectura del ciclo de right-sizing en AKS: el Prometheus gestionado de Azure Monitor mide el uso p95, FluxCD aplica los nuevos requests desde Git, el cluster autoscaler reduce el node pool, Cost Management envía un informe diario y se compran reservas para el tamaño nuevo.

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.

promql
# 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.

yaml
# 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 fair

Consejo 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 checklists

4. 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.

Workload Autoscaling, AKS Cost Management Series, Episode 3, Azure Kubernetes Service (AKS) (YouTube). Se carga desde YouTube solo cuando haces clic.

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.

bash
# 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 6

Consejo 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.

Más artículos

    Hablemos

    Cuéntame qué estás construyendo; te respondo en 1 o 2 días laborables.

    Dominik Heinrich
    Empresa
    MADO Consulting

    Disponible en todo el mundo en remoto. Presencial bajo petición, según el país.

    Te respondo en 1 o 2 días laborables. Huecos libres: mira el calendario

    Abre aquí el calendario de reservas de Calendly. Al cargarlo se envían datos a Calendly (ver aviso legal).