We are at re:Invent 2026Book my merch

Cloud Intelligence™

O recurso do GKE que a maioria dos clusters ainda não usa: ComputeClasses personalizadas

Esta página também está disponível em English, Deutsch, Español, Français, Italiano e 日本語.

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

Vejo o mesmo padrão em quase toda análise de cluster GKE que faço: uma longa lista de node pools estáticos, cada um atrelado a um único tipo de máquina. Um pool n2-standard-8 para workloads gerais, um pool n2-highmem-16 para os serviços que consomem muita memória, um pool Spot que alguém criou durante uma campanha de redução de custos no ano passado e, talvez, um pool de GPU. Os workloads são agendados nos nós por meio de nodeSelector, taints, tolerations e regras de node affinity acumuladas ao longo dos anos.

Tudo se sustenta até que algo mude — e geralmente é uma destas três coisas.

  • Esgotamento de capacidade por zona (stockouts): Uma zona fica sem a série de máquinas que você escolheu. O Cluster Autoscaler só consegue escalar os pools específicos que você configurou, deixando Pods presos em Pending mesmo com famílias de máquinas vizinhas ociosas na mesma zona.

  • Armadilhas de preempção do Spot: Preempções intensas de Spot empurram workloads para pools de fallback on-demand. Quando a capacidade se recupera, nada migra os workloads de volta ativamente, então a economia que você planejou nunca aparece na fatura.

  • Upgrades geracionais: Migrar de N2 para N4 ou C4 vira uma maratona operacional de várias semanas: provisionar novos pools, atualizar valores de Helm em dezenas de repositórios, drenar nós antigos e torcer para que nenhum manifesto tenha labels antigas hardcoded.

O GKE já tem uma resposta para esses três problemas há algum tempo: as ComputeClasses personalizadas. Os clientes com quem converso ou nunca ouviram falar delas, ou acham que são exclusivas do Autopilot. Não são. As ComputeClasses personalizadas estão disponíveis tanto no modo Autopilot quanto no Standard a partir do GKE 1.30.3-gke.1451000, e vêm habilitadas por padrão em todos os clusters elegíveis.

O que é uma ComputeClass personalizada?

Uma ComputeClass é um recurso personalizado do Kubernetes (computeclasses.cloud.google.com) que especifica quais perfis de nó os workloads preferem, classificados por prioridade. Como explica a documentação do Google, ela fornece ao GKE um perfil de atributos de nó para usar durante eventos de autoscaling.

  • Node pools tradicionais: Você declara a infraestrutura primeiro e depois direciona os workloads para ela.

  • ComputeClasses: Você declara a intenção desejada ("Tente N4 Spot primeiro; se não estiver disponível, tente C4 Spot; caso contrário, use N4 on-demand como fallback"), e o autoscaler provisiona os nós certos automaticamente.

Isso mantém as responsabilidades separadas: times de plataforma definem perfis de hardware e desenvolvedores de aplicação escolhem um perfil pelo nome.

O que isso resolve na prática

  • Stockouts viram fallbacks automatizados: Se uma regra de alta prioridade falhar por cota ou disponibilidade zonal, o GKE tenta imediatamente a próxima regra da lista.
  • A capacidade de fallback não fica parada: Com a migração ativa habilitada, o GKE move os workloads de volta para nós de maior prioridade assim que a capacidade preferida retorna, recuperando a economia automaticamente.
  • Upgrades ficam do lado da plataforma: Migrar workloads de N2 para N4, ou testar C4, significa atualizar um único manifesto de ComputeClass. Os times de aplicação nunca precisam mexer nos seus selectors.

Alguns detalhes menores também ajudam. Você pode decidir centralmente quais reservas do Compute Engine são consumidas primeiro, ajustar a agressividade com que cada classe consolida nós subutilizados e definir uma classe padrão para um namespace ou para o cluster inteiro, de modo que os times recebam hardware adequado sem escrever um selector.

Principais opções de configuração

Em spec.priorities, cada regra define um alvo de hardware principal: machineFamily (por exemplo, n4), machineType (por exemplo, n4-standard-32), gpu ou tpu. Em clusters Standard, uma regra pode apontar para node pools existentes com nodepools. As regras aceitam flags para spot, minCores, minMemoryGb, configurações de disco de boot, SSDs locais, discos de boot secundários, reservas e zonas.

  • whenUnsatisfiable: Controla o comportamento se todos os níveis de prioridade falharem. ScaleUpAnyway cria um nó com a configuração padrão do cluster, enquanto DoNotScaleUp deixa os Pods pendentes até que um nó compatível possa ser criado. DoNotScaleUp é o padrão desde o GKE 1.33 (antes disso, era ScaleUpAnyway), então defina-o explicitamente para evitar surpresas quando clusters em versões diferentes compartilham os mesmos manifestos.

  • autoscalingPolicy: Configura a sensibilidade de scale-down com consolidationDelayMinutes, um consolidationThreshold de CPU e memória e um gpuConsolidationThreshold separado.

  • activeMigration: A migração ativa tem duas chaves.

    • optimizeRulePriority: true move os Pods de volta ativamente para nós de maior prioridade conforme a capacidade é liberada.
    • ensureAllDaemonSetPodsRunning: true substitui por nós maiores os nós pequenos demais para executar todos os Pods de DaemonSet necessários.
  • nodePoolAutoCreation.enabled: true: Permite que o GKE crie e exclua node pools para atender às suas prioridades. A partir do GKE 1.33.3-gke.1136000, não é mais necessário ter o node auto-provisioning habilitado no nível do cluster para isso.

Seus pools existentes continuam funcionando. Adicione a label cloud.google.com/compute-class e um taint NoSchedule correspondente a um pool criado manualmente e ele passa a fazer parte da classe — assim você pode adotar as classes gradualmente.

Você também pode aplicar uma ComputeClass por padrão a um namespace adicionando uma label a ele, ou ao cluster inteiro implantando uma classe chamada default e habilitando o recurso no cluster. O GKE também traz ComputeClasses integradas, incluindo a autopilot, que permite que clusters Standard executem Pods selecionados na plataforma de computação otimizada para contêineres do Autopilot.

Dois padrões para começar

Padrão 1: Substituir pools Spot estáticos por uma cadeia de fallback resiliente

Aqui está uma ComputeClass de uso geral que prioriza N4 Spot, usa C4 Spot como fallback e mantém N4 on-demand como válvula de segurança. Ela consolida nós subutilizados após 5 minutos e migra os Pods de volta pela cadeia quando a capacidade 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

Com optimizeRulePriority: true, o GKE move os Pods de volta para a regra Spot preferida assim que a capacidade retorna e, em seguida, remove o nó de fallback.

Os workloads consomem essa classe por meio de um ú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"

Não há selector cloud.google.com/gke-spot, nem tolerations, nem affinity de família de máquinas — e isso é proposital. O GKE rejeita Pods que selecionam uma ComputeClass e, ao mesmo tempo, selecionam labels de sistema que têm um campo correspondente na ComputeClass, como cloud.google.com/gke-spot, cloud.google.com/machine-family ou node.kubernetes.io/instance-type. Essas escolhas pertencem à classe. Se você estiver migrando workloads existentes, procure primeiro essas labels nos seus manifestos e Helm charts.

Padrão 2: Sobrepor classes a pools personalizados existentes

Se você opera clusters Standard com pools especializados, pré-aquecidos ou respaldados por reservas, não precisa excluí-los. Configure a classe para usar os pools existentes primeiro e criar novos apenas quando eles não puderem 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

Adicione a label e o taint ao seu pool existente para que a classe o reconheça:

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"

Observe que --node-labels e --node-taints substituem todas as labels e taints do pool, então inclua as já existentes ao executar esses comandos.

O guia de práticas recomendadas sugere a mesma ordem: pools criados manualmente recebem a prioridade mais alta e pools criados automaticamente ficam como fallback.

Cloud bill shouldn't be a mystery

One platform for AI and Cloud optimization.

Novidades recentes que valem destaque

O recurso evoluiu rápido nas últimas versões minor do GKE. Estas são as mudanças que eu destacaria para quem avaliou as ComputeClasses há um ano e deixou de lado.

Pontuações de prioridade ponderadas (1.35.2-gke.1842000+)

Em vez de depender apenas da ordem da lista, as regras podem definir um priorityScore explícito de 1 a 1000. É tudo ou nada: ou todas as regras da classe têm pontuação, ou nenhuma tem. Até três regras podem compartilhar a mesma pontuação, e o GKE avalia as regras empatadas em conjunto, deixando o Cluster Autoscaler escolher entre elas.

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

Aqui, N2 e T2D Spot contam como segundas opções igualmente boas. Regras agrupadas podem aumentar a latência do autoscaling — mais em regras amplas de machineFamily do que em regras restritas de machineType —, porque o GKE precisa executar mais simulações.

Seleção automática de armazenamento (1.35.3-gke.1290000+)

Misturar gerações de máquinas costumava trazer um risco de armazenamento, porque cada série suporta tipos de disco específicos (por exemplo, a N4 suporta Hyperdisk, enquanto a N2 depende de PDs padrão). Agora você pode usar uma StorageClass com seleção automatizada de tipo de disco, e o GKE cria um tipo de disco compatível com qualquer tipo de máquina em que o Pod for alocado. Isso torna as cadeias de fallback multigeracionais muito mais seguras para workloads que usam provisionamento dinâmico. Discos preexistentes ainda precisam de um tipo de disco suportado por todas as séries de máquinas da classe.

Formatos de máquina personalizados (1.33.2-gke.1111000+)

Você pode definir formatos personalizados como n4-custom-8-20480 diretamente em machineType, para workloads cuja proporção entre CPU e memória não se encaixa nos formatos predefinidos.

Configurações de disco de boot em regras machineFamily (1.34.1-gke.1431000+)

Defina storage.bootDiskType e storage.bootDiskSize em regras flexíveis de machineFamily, em vez de apenas em regras específicas de machineType:

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

Labels e taints na classe (1.33.2 a 1.34.1)

Declare nodeLabels e taints por regra de prioridade (labels a partir da 1.33.2-gke.1111000, taints a partir da 1.33.4-gke.1350000) ou globalmente em nodePoolConfig (a partir da 1.34.1-gke.3084002). Os valores por regra e os globais não podem se sobrepor. Isso mantém a rotulagem e o isolamento no mesmo objeto da decisão de hardware.

Classes padrão para workloads de sistema (1.33.1-gke.1788000+)

Namespaces podem receber uma classe padrão que se aplica apenas a Pods que não são de DaemonSet, usando a label cloud.google.com/default-compute-class-non-daemonset. O GKE usa isso para executar Pods de sistema em namespaces como kube-system e gmp-system separadamente dos seus workloads, enquanto os Pods de DaemonSet não recebem o selector da classe.

Computação do Autopilot junto com um padrão personalizado (1.34.1-gke.1829001+)

Se você definir uma classe personalizada como padrão do cluster em um cluster Autopilot, os Pods deixam de executar por padrão na plataforma otimizada para contêineres do Autopilot. Agora é possível executar a plataforma de computação do Autopilot para Pods específicos adicionando o node selector cloud.google.com/compute-class: autopilot a esses Pods.

Algumas adições menores

O priorityDefaults (1.32.1-gke.1729000) permite definir valores compartilhados uma única vez, em vez de repeti-los em cada regra. O nodeSystemConfig traz ajustes de kubelet e sysctl para dentro da classe. Compact placement e workload policies estão disponíveis para o Autopilot a partir da 1.33.2-gke.1335000.

Ressalvas de produção e casos extremos

As ComputeClasses têm limites, e é melhor descobri-los em uma revisão de design, não em produção.

  • O kube-scheduler não conhece as regras de prioridade: As ComputeClasses influenciam o autoscaling, mas o kube-scheduler não as considera. Se os nós de fallback já tiverem capacidade, novos Pods podem ser alocados neles antes dos nós preferidos. Habilitar activeMigration.optimizeRulePriority substitui esses nós de fallback com o tempo, e um consolidationThreshold mais rigoroso ajuda os nós de fallback subutilizados a serem drenados mais cedo.

  • As mudanças valem apenas daqui para frente: Editar uma ComputeClass não altera os nós em execução. Faça cordon e drain dos nós existentes durante uma janela de manutenção para que sejam substituídos sob as novas regras.

  • Mantenha workloads stateful fora da migração ativa: A migração ativa despeja os Pods e não move os dados. O guia de práticas recomendadas orienta desabilitá-la em classes usadas por workloads stateful. Coloque esses workloads em uma classe dedicada e use a seleção automatizada de tipo de disco, ou limite a classe a séries de máquinas que sejam todas compatíveis com o seu tipo de disco.

  • Padrões de namespace não migram Pods existentes: O GKE injeta o selector da classe apenas em Pods criados depois que você adiciona a label ao namespace, então os Pods já em execução permanecem intactos. Reinicie os workloads do namespace após definir um padrão, para que os Pods recriados recebam o selector e a migração ativa. Um padrão no nível do cluster pode migrar Pods existentes diretamente.

  • Atenção ao churn elevado de Pods: Em clusters com taxas muito altas de criação e exclusão de Pods, o Cluster Autoscaler pode não avaliar as regras inferiores antes que o backoff das regras superiores expire, e os Pods ficam em Pending. Se você encontrar esse caso extremo, reduza a frequência de consolidação ou desabilite a migração ativa.

  • Comportamento de fallback de reservas: Com AnyBestEffort, se nenhuma reserva compatível tiver capacidade, o GKE tenta um nó on-demand para essa mesma regra antes de passar para a próxima. Para cair direto na próxima regra quando a capacidade reservada estiver esgotada, use affinity: Specific (para reservas nomeadas) ou affinity: AnyThenFail.

Restrições menores

Um workload pode selecionar apenas uma ComputeClass, e cada node pool criado manualmente pode pertencer a apenas uma. No Autopilot, bootDiskType suporta apenas pd-balanced. Os nomes de classe não podem começar com gke ou autopilot. Muitos dos recursos acima exigem versões de patch recentes, então verifique seu canal de lançamento antes de projetar sua arquitetura com base neles.

Conclusão

Se seus clusters ainda rodam em node pools fixos atrelados a tipos de máquina, comece com um namespace stateless. Dê a ele uma cadeia de fallback com Spot em primeiro lugar e observe com que frequência os Pods caem nas regras de fallback e se a migração ativa os move de volta.

Lembre-se de que uma ComputeClass decide que tipo de nó criar, mas o tamanho do nó depende dos resource requests dos seus Pods. Para regras de machineFamily, o Cluster Autoscaler escolhe um tamanho de máquina com base nos requests agregados dos Pods pendentes. Requests superdimensionados significam máquinas maiores, bin packing pior e um footprint de fallback maior.

É aí que o right-sizing compensa. O PerfectScale ajusta continuamente os requests dos workloads, para que os nós criados pelas suas ComputeClasses correspondam ao que seus Pods realmente usam. Seu recurso de Node Recommendations ajuda a escolher as famílias de máquinas mais econômicas para incluir nas suas regras de prioridade. Se você está auditando os gastos do cluster e quer ver como essas configurações de fallback se comportam na prática, agende uma demo com o time.

Referências