We are at re:Invent 2026Book my merch

Cloud Intelligence™

La funcionalidad de GKE que la mayoría de los clústeres aún no usa: ComputeClasses personalizadas

Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.

Nov 13, 202611 min read
Chimbu Chinnadurai

About Chimbu Chinnadurai

Senior Cloud Architect II

I've probably debugged a Kubernetes issue in more time zones than I care to count. Based in London, I help engineering teams across EMEA get their clusters to behave — and actually understand why they misbehaved in the first place.

I write, speak, and guest on podcasts about all things cloud-native. Away from the terminal: I enjoy cooking almost as much as simplifying overly complex systems.

My personal page

Veo el mismo patrón en casi todas las revisiones de clústeres de GKE que hago: una larga lista de node pools estáticos, cada uno atado a un solo tipo de máquina. Un pool n2-standard-8 para workloads generales, un pool n2-highmem-16 para los servicios que consumen mucha memoria, un pool de Spot que alguien creó durante una campaña de ahorro el año pasado y, quizás, un pool de GPU. Los workloads se programan en los nodos mediante nodeSelector, taints, tolerations y reglas de node affinity acumuladas a lo largo de los años.

Todo se sostiene hasta que algo cambia, y suele ser una de estas tres cosas.

  • Agotamiento de capacidad zonal: Una zona se queda sin capacidad de la serie de máquinas que elegiste. El Cluster Autoscaler solo puede escalar los pools específicos que le diste, y los pods quedan atascados en Pending incluso cuando hay familias de máquinas vecinas ociosas en la misma zona.

  • Trampas de preempción de Spot: Las preempciones masivas de Spot desbordan los workloads hacia pools de fallback on-demand. Cuando la capacidad se recupera, nada migra los workloads de vuelta de forma activa, así que el ahorro que planificaste nunca aparece en la factura.

  • Upgrades generacionales: Pasar de N2 a N4 o C4 se convierte en una tarea operativa de varias semanas: aprovisionar pools nuevos, actualizar valores de Helm en docenas de repositorios, drenar nodos viejos y cruzar los dedos para que ningún manifiesto tenga labels antiguas hardcodeadas.

GKE tiene desde hace un tiempo una respuesta para los tres problemas: las ComputeClasses personalizadas. Los clientes con los que hablo o no han oído de ellas o asumen que son exclusivas de Autopilot. No lo son. Las ComputeClasses personalizadas están disponibles tanto en modo Autopilot como Standard desde GKE 1.30.3-gke.1451000, y vienen habilitadas por defecto en todos los clústeres elegibles.

¿Qué es una ComputeClass personalizada?

Una ComputeClass es un recurso personalizado de Kubernetes (computeclasses.cloud.google.com) que especifica qué perfiles de nodo prefieren los workloads, ordenados por prioridad. Como explica la documentación de Google, le entrega a GKE un perfil de atributos de nodo para usar durante los eventos de autoscaling.

  • Node pools tradicionales: Primero declaras la infraestructura y luego diriges los workloads hacia ella.

  • ComputeClasses: Declaras tu intención ("Intenta primero N4 Spot; si no hay disponibilidad, prueba C4 Spot; si no, recurre a N4 on-demand") y el autoscaler aprovisiona los nodos correctos automáticamente.

Así se mantienen las responsabilidades separadas: los equipos de plataforma definen perfiles de hardware y los desarrolladores de aplicaciones eligen un perfil por nombre.

Qué resuelve en la práctica

  • Los agotamientos de capacidad se convierten en fallbacks automatizados: Si una regla de alta prioridad falla por cuota o disponibilidad zonal, GKE intenta de inmediato la siguiente regla de la lista.
  • La capacidad de fallback no se eterniza: Con la migración activa habilitada, GKE devuelve los workloads a los nodos de mayor prioridad en cuanto regresa la capacidad preferida, y el ahorro se recupera automáticamente.
  • Los upgrades se quedan del lado de la plataforma: Mover workloads de N2 a N4, o probar C4, implica actualizar un solo manifiesto de ComputeClass. Los equipos de aplicaciones nunca tocan sus selectores.

También ayudan algunos detalles menores. Puedes decidir de forma centralizada qué reservas de Compute Engine se consumen primero, ajustar qué tan agresivamente consolida cada clase los nodos subutilizados y establecer una clase por defecto para un namespace o para todo el clúster, de modo que los equipos reciban hardware razonable sin escribir un selector.

Los ajustes de configuración clave

Bajo spec.priorities, cada regla define un objetivo de hardware principal: machineFamily (por ejemplo n4), machineType (por ejemplo n4-standard-32), gpu o tpu. En clústeres Standard, una regla puede apuntar a node pools existentes con nodepools. Las reglas aceptan flags para spot, minCores, minMemoryGb, configuración del disco de arranque, SSDs locales, discos de arranque secundarios, reservas y zonas.

  • whenUnsatisfiable: Controla el comportamiento si todos los niveles de prioridad fallan. ScaleUpAnyway crea un nodo con la configuración por defecto del clúster, mientras que DoNotScaleUp deja los Pods pendientes hasta que se pueda crear un nodo que cumpla las reglas. DoNotScaleUp es el valor por defecto desde GKE 1.33 (antes era ScaleUpAnyway), así que defínelo explícitamente para evitar sorpresas cuando clústeres en versiones distintas comparten los mismos manifiestos.

  • autoscalingPolicy: Configura la sensibilidad del scale-down con consolidationDelayMinutes, un consolidationThreshold de CPU y memoria, y un gpuConsolidationThreshold independiente.

  • activeMigration: La migración activa tiene dos ajustes.

    • optimizeRulePriority: true devuelve los pods de forma activa a los nodos de mayor prioridad a medida que se libera capacidad.
    • ensureAllDaemonSetPodsRunning: true reemplaza con nodos más grandes aquellos que son demasiado pequeños para ejecutar todos los Pods de DaemonSet requeridos.
  • nodePoolAutoCreation.enabled: true: Permite que GKE cree y elimine node pools para satisfacer tus prioridades. Desde GKE 1.33.3-gke.1136000, ya no necesitas tener habilitado el aprovisionamiento automático de nodos a nivel de clúster para esto.

Tus pools existentes siguen funcionando. Agrega la label cloud.google.com/compute-class y un taint NoSchedule correspondiente a un pool creado manualmente y este se incorpora a la clase, así que puedes adoptar las clases de forma gradual.

También puedes aplicar una ComputeClass por defecto a un namespace etiquetándolo, o a todo el clúster desplegando una clase llamada default y habilitando la funcionalidad en el clúster. GKE además incluye ComputeClasses integradas, entre ellas autopilot, que permite que los clústeres Standard ejecuten Pods seleccionados en la plataforma de cómputo optimizada para contenedores de Autopilot.

Dos patrones para empezar

Patrón 1: Reemplazar pools de Spot estáticos con una cadena de fallback resiliente

Aquí tienes una clase de cómputo de propósito general que prioriza N4 Spot, recurre a C4 Spot y usa N4 on-demand como válvula de seguridad. Consolida los nodos subutilizados después de 5 minutos y migra los pods de vuelta hacia arriba en la cadena cuando la capacidad de Spot se recupera:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
name: general-cost-optimized
spec:
nodePoolAutoCreation:
enabled: true
priorities:
- machineFamily: n4
spot: true
minCores: 4
- machineFamily: c4
spot: true
minCores: 4
- machineFamily: n4
spot: false
activeMigration:
optimizeRulePriority: true
autoscalingPolicy:
consolidationDelayMinutes: 5
consolidationThreshold: 70
whenUnsatisfiable: DoNotScaleUp

Con optimizeRulePriority: true, GKE devuelve los Pods a la regla de Spot preferida en cuanto regresa la capacidad y luego elimina el nodo de fallback.

Los workloads consumen esta clase a través de un único node selector:

apiVersion: apps/v1
kind: Deployment
metadata:
name: checkout-api
spec:
replicas: 3
selector:
matchLabels:
app: checkout-api
template:
metadata:
labels:
app: checkout-api
spec:
nodeSelector:
cloud.google.com/compute-class: general-cost-optimized
containers:
- name: api
image: registry.k8s.io/pause
resources:
requests:
cpu: "1"
memory: "2Gi"

No hay selector cloud.google.com/gke-spot, ni tolerations, ni affinity de familia de máquinas, y es a propósito. GKE rechaza los Pods que seleccionan una ComputeClass y a la vez seleccionan labels de sistema que tienen un campo equivalente en la ComputeClass, como cloud.google.com/gke-spot, cloud.google.com/machine-family o node.kubernetes.io/instance-type. Esas decisiones viven dentro de la clase. Si estás migrando workloads existentes, primero busca estas labels en tus manifiestos y charts de Helm.

Patrón 2: Superponer clases sobre pools personalizados existentes

Si operas clústeres Standard con pools especializados, precalentados o respaldados por reservas, no necesitas eliminarlos. Configura la clase para usar primero los pools existentes y crear nuevos solo cuando aquellos no puedan escalar:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
name: hybrid-fallback-class
spec:
nodePoolAutoCreation:
enabled: true
priorities:
- nodepools: [core-workload-pool]
- machineFamily: n4
- machineFamily: c4

Etiqueta y agrega el taint a tu pool existente para que la clase lo reconozca:

gcloud container node-pools update core-workload-pool \
--cluster=example-cluster \
--node-labels="cloud.google.com/compute-class=hybrid-fallback-class"
gcloud container node-pools update core-workload-pool \
--cluster=example-cluster \
--node-taints="cloud.google.com/compute-class=hybrid-fallback-class:NoSchedule"

Ten en cuenta que --node-labels y --node-taints reemplazan todas las labels y taints del pool, así que incluye las labels y taints existentes al ejecutar estos comandos.

La guía de buenas prácticas recomienda el mismo orden: los pools creados manualmente reciben la prioridad más alta y los pools creados automáticamente son el fallback.

Cloud bill shouldn't be a mystery

One platform for AI and Cloud optimization.

Novedades recientes destacadas

La funcionalidad ha avanzado rápido en las últimas versiones menores de GKE. Estos son los cambios que le destacaría a cualquiera que haya mirado las ComputeClasses hace un año y haya pasado de largo.

Puntajes de prioridad ponderados (1.35.2-gke.1842000+)

En lugar de depender solo del orden de la lista, las reglas pueden definir un priorityScore explícito de 1 a 1000. Es todo o nada: o todas las reglas de la clase tienen puntaje, o ninguna. Hasta tres reglas pueden compartir un mismo puntaje, y GKE evalúa en conjunto las reglas empatadas, dejando que el Cluster Autoscaler elija entre ellas.

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
name: priority-rule-score-class
spec:
nodePoolAutoCreation:
enabled: true
priorities:
- machineFamily: e2
spot: true
priorityScore: 30
- machineFamily: n2
spot: true
priorityScore: 20
- machineFamily: t2d
spot: true
priorityScore: 20
- machineFamily: n1
spot: true
priorityScore: 10
whenUnsatisfiable: ScaleUpAnyway

Aquí N2 y T2D Spot cuentan como segundas opciones igual de buenas. Las reglas agrupadas pueden añadir latencia al autoscaling, más en reglas amplias de machineFamily que en reglas acotadas de machineType, porque GKE debe ejecutar más simulaciones.

Selección automática de almacenamiento (1.35.3-gke.1290000+)

Mezclar generaciones de máquinas solía implicar un riesgo de almacenamiento, porque cada serie admite tipos de disco específicos (por ejemplo, N4 soporta Hyperdisk, mientras que N2 depende de PDs estándar). Ahora puedes usar una StorageClass con selección automatizada del tipo de disco, y GKE crea un tipo de disco compatible con el tipo de máquina en el que termine el Pod. Esto hace que las cadenas de fallback multigeneración sean mucho más seguras para workloads que usan aprovisionamiento dinámico. Los discos preexistentes siguen necesitando un tipo de disco compatible con todas las series de máquinas de la clase.

Formas de máquina personalizadas (1.33.2-gke.1111000+)

Puedes definir formas personalizadas como n4-custom-8-20480 directamente en machineType, para workloads cuya relación CPU-memoria no encaja en las formas predefinidas.

Configuración del disco de arranque en reglas machineFamily (1.34.1-gke.1431000+)

Define storage.bootDiskType y storage.bootDiskSize en reglas flexibles de machineFamily, no solo en reglas específicas de machineType:

priorities:
- machineFamily: n4
spot: true
minCores: 16
minMemoryGb: 64
storage:
bootDiskType: hyperdisk-balanced
bootDiskSize: 100

Labels y taints dentro de la clase (1.33.2 a 1.34.1)

Declara nodeLabels y taints por regla de prioridad (labels desde 1.33.2-gke.1111000, taints desde 1.33.4-gke.1350000) o de forma global bajo nodePoolConfig (desde 1.34.1-gke.3084002). Los valores a nivel de regla y los globales no deben superponerse. Así, el etiquetado y el aislamiento viven en el mismo objeto que la decisión de hardware.

Clases por defecto para workloads de sistema (1.33.1-gke.1788000+)

Los namespaces pueden recibir una clase por defecto que aplica solo a Pods que no son de DaemonSet, usando la label cloud.google.com/default-compute-class-non-daemonset. GKE la usa para ejecutar los Pods de sistema en namespaces como kube-system y gmp-system de forma separada de tus workloads, mientras que a los Pods de DaemonSet no se les asigna el selector de la clase.

Cómputo de Autopilot junto a un default personalizado (1.34.1-gke.1829001+)

Si estableces una clase personalizada como default del clúster en un clúster de Autopilot, los Pods dejan de ejecutarse por defecto en la plataforma optimizada para contenedores de Autopilot. Ahora puedes usar la plataforma de cómputo de Autopilot para Pods específicos agregándoles el node selector cloud.google.com/compute-class: autopilot.

Algunas novedades menores

priorityDefaults (1.32.1-gke.1729000) te permite establecer valores compartidos una sola vez en lugar de repetirlos en cada regla. nodeSystemConfig incorpora el ajuste de kubelet y sysctl a la clase. El compact placement y las políticas de workloads están disponibles para Autopilot desde 1.33.2-gke.1335000.

Advertencias para producción y casos límite

Las ComputeClasses tienen límites, y es mejor encontrarlos en una revisión de diseño, no en producción.

  • kube-scheduler no conoce las reglas de prioridad: Las ComputeClasses influyen en el autoscaling, pero kube-scheduler no las tiene en cuenta. Si los nodos de fallback ya tienen capacidad, los Pods nuevos pueden terminar en ellos antes que en los nodos preferidos. Habilitar activeMigration.optimizeRulePriority reemplaza esos nodos de fallback con el tiempo, y un consolidationThreshold más estricto ayuda a que los nodos de fallback subutilizados se drenen antes.

  • Los cambios solo aplican hacia adelante: Editar una ComputeClass no altera los nodos en ejecución. Haz cordon y drain de los nodos existentes durante una ventana de mantenimiento para que se reemplacen bajo las nuevas reglas.

  • Mantén los workloads con estado fuera de la migración activa: La migración activa desaloja Pods y no mueve datos. La guía de buenas prácticas indica deshabilitarla en clases usadas por workloads con estado. Pon esos workloads en una clase dedicada y usa la selección automatizada del tipo de disco, o limita la clase a series de máquinas que todas soporten tu tipo de disco.

  • Los defaults de namespace no migran Pods existentes: GKE inyecta el selector de la clase solo en los Pods creados después de etiquetar el namespace, así que los Pods que ya están en ejecución quedan intactos. Reinicia los workloads del namespace tras establecer un default para que los Pods recreados adopten el selector y la migración activa. Un default a nivel de clúster sí puede migrar Pods existentes directamente.

  • Cuidado con la alta rotación de Pods: En clústeres con tasas muy altas de creación y eliminación de Pods, puede que el Cluster Autoscaler no alcance a evaluar las reglas inferiores antes de que expire el backoff de las reglas superiores, y los Pods se quedan en Pending. Si te topas con este caso límite, reduce la frecuencia de consolidación o deshabilita la migración activa.

  • Comportamiento de fallback con reservas: Con AnyBestEffort, si ninguna reserva coincidente tiene capacidad, GKE intenta un nodo on-demand para esa misma regla antes de pasar a la siguiente. Para saltar directamente a la regla siguiente cuando la capacidad reservada está llena, usa affinity: Specific (para reservas con nombre) o affinity: AnyThenFail.

Restricciones menores

Un workload puede seleccionar una sola ComputeClass, y cada node pool creado manualmente puede pertenecer solo a una. En Autopilot, bootDiskType solo admite pd-balanced. Los nombres de clase no pueden empezar con gke ni autopilot. Muchas de las funcionalidades anteriores requieren versiones de parche recientes, así que verifica tu canal de versiones antes de diseñar en torno a ellas.

Conclusión

Si tus clústeres todavía corren sobre node pools fijos atados a tipos de máquina, empieza con un namespace sin estado. Dale una cadena de fallback con Spot primero y luego observa con qué frecuencia los Pods caen en las reglas de fallback y si la migración activa los devuelve.

Ten presente que una ComputeClass decide qué tipo de nodo crear, pero el tamaño del nodo depende de los resource requests de tus Pods. En las reglas de machineFamily, el Cluster Autoscaler elige un tamaño de máquina según las solicitudes agregadas de los Pods pendientes. Los requests sobredimensionados implican máquinas más grandes, peor bin packing y una huella de fallback mayor.

Ahí es donde el rightsizing da frutos. PerfectScale ajusta continuamente los requests de tus workloads, de modo que los nodos que crean tus ComputeClasses coincidan con lo que tus Pods realmente usan. Su funcionalidad de Node Recommendations te ayuda a elegir las familias de máquinas más rentables para incluir en tus reglas de prioridad. Si estás auditando el gasto de tus clústeres y quieres ver cómo rinden estas configuraciones de fallback en la práctica, agenda una demo con el equipo.

Referencias