PerfectScalePerfectScale

PerfectScale

Guia definitivo de Node Affinity: exemplos, casos de uso e dicas de especialista

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

Aug 30, 202612 min read
Josh Palmer

About Josh Palmer

Head of Content

I'm Josh Palmer, Head of Content at DoiT, where I split my time across multiple business units including DoiT Cloud Intelligence, PerfectScale (Kubernetes cost optimization), and SELECT (Snowflake, Databricks, and BigQuery cost optimization). Before DoiT, I spent four and a half years at OnBoard building content for a board intelligence platform used by 6,000+ organizations, and before that, two years as Content Marketing Manager at Zylo, a SaaS management platform.

My personal page

Resumo: Node affinity permite restringir em quais nós um pod pode rodar com base nos labels dos nós, usando regras hard (requiredDuringSchedulingIgnoredDuringExecution) ou soft (preferredDuringSchedulingIgnoredDuringExecution). É mais expressivo que o nodeSelector e costuma ser usado para direcionar pods a nós com GPU/SSD, manter workloads em uma zona específica ou separar produção de desenvolvimento. Padronize os labels dos nós, prefira regras soft a menos que o posicionamento seja obrigatório e alinhe a afinidade com o autoscaling e o dimensionamento dos workloads para evitar pods presos em Pending.

Neste artigo:

O que é node affinity no Kubernetes?

Node affinity no Kubernetes é um conjunto de regras usado para restringir em quais nós um pod pode ser agendado, com base nos labels atribuídos aos nós. Ele permite uma lógica de agendamento mais expressiva e complexa que o nodeSelector, com suporte tanto a regras soft quanto a regras hard para posicionar pods em hardware específico e devidamente rotulado, como SSDs ou GPUs.

Esse recurso é especialmente útil em clusters Kubernetes multi-tenant, híbridos ou heterogêneos, em que os workloads podem ter requisitos variados de hardware ou de localidade. O node affinity permite otimizar a utilização de recursos, isolar workloads sensíveis e melhorar o desempenho das aplicações ao direcionar cada workload para os nós com as características mais adequadas.

Principais tipos de node affinity:

  • Regras hard (requiredDuringSchedulingIgnoredDuringExecution): o scheduler precisa encontrar um nó compatível para posicionar o pod; caso contrário, ele permanece em estado pendente.
  • Regras soft (preferredDuringSchedulingIgnoredDuringExecution): o scheduler tenta encontrar um nó compatível, mas, se nenhum estiver disponível, agenda o pod em outro lugar mesmo assim.

Exemplo de uso (YAML):

spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd

Este conteúdo faz parte de uma série de artigos sobre agendamento no Kubernetes.

Como o node affinity funciona no Kubernetes

Estes são os principais elementos técnicos por trás do node affinity.

Labels de nós

Labels de nós são pares chave-valor anexados aos nós do Kubernetes para descrever seus atributos. Os labels são arbitrários e podem representar características como tipo de instância, região, zona de disponibilidade ou metadados personalizados relevantes para o agendamento de workloads. Por exemplo, você pode rotular nós com disktype=ssd ou gpu=true para identificar nós com armazenamento SSD ou aceleração por GPU.

Os labels são definidos por administradores do cluster ou por scripts de automação, seja quando os nós são adicionados ao cluster, seja dinamicamente, conforme a infraestrutura muda. Uma rotulagem consistente e significativa é essencial para que o node affinity funcione bem, já que as regras de afinidade dependem desses labels para selecionar os nós apropriados para o posicionamento dos pods. Uma rotulagem adequada garante que o scheduler consiga interpretar e aplicar corretamente suas políticas de posicionamento.

Operadores de node affinity

As regras de node affinity usam operadores para definir como os pods devem corresponder aos labels dos nós. Os operadores mais comuns são In, NotIn, Exists e DoesNotExist. Os operadores In e NotIn permitem especificar valores aceitáveis ou inaceitáveis para um determinado label, enquanto Exists e DoesNotExist verificam a presença ou a ausência de uma chave de label, independentemente do valor.

Esses operadores oferecem flexibilidade para expressar requisitos de agendamento complexos. Por exemplo, você pode exigir que os pods rodem apenas em nós onde environment=production ou evitar nós com dedicated=backup. Combinando diferentes operadores e seletores de labels, é possível ajustar com precisão o posicionamento dos pods para atender aos requisitos dos workloads e às políticas da organização.

Comportamento do scheduler

O scheduler do Kubernetes avalia as regras de node affinity ao decidir onde posicionar um pod. Ele compara os labels dos nós disponíveis com os critérios de afinidade definidos na especificação do pod. Se um nó satisfaz as regras de afinidade obrigatórias, ele se torna elegível para receber o pod; caso contrário, o pod permanece sem agendamento até que um nó adequado esteja disponível.

Existem dois tipos de node affinity: required (hard) e preferred (soft). As regras required precisam ser satisfeitas para que o pod seja agendado, enquanto as regras preferred influenciam a escolha do scheduler, mas não impedem o agendamento caso nenhum nó preferido esteja disponível. Essa distinção permite estratégias de posicionamento tanto rígidas quanto flexíveis, equilibrando necessidades operacionais e disponibilidade de recursos.

Sintaxe YAML de node affinity: regras hard vs. soft

1. RequiredDuringSchedulingIgnoredDuringExecution

requiredDuringSchedulingIgnoredDuringExecution define regras hard de node affinity que precisam ser atendidas antes que um pod possa ser agendado em um nó. O scheduler considera apenas nós cujos labels correspondam a todas as condições especificadas. Se nenhum nó compatível estiver disponível, o pod permanece em estado Pending até que um nó adequado apareça.

Esse tipo de afinidade costuma ser usado para workloads com requisitos rígidos de infraestrutura. Por exemplo, uma aplicação de machine learning pode exigir nós com GPUs, ou um workload sensível a compliance pode precisar rodar apenas em uma região ou zona de disponibilidade específica.

A parte IgnoredDuringExecution significa que o Kubernetes não remove o pod caso os labels do nó mudem após o agendamento. Se um label do nó for removido ou modificado depois, o pod em execução continua operando naquele nó, a menos que outro mecanismo acione o reagendamento.

Exemplo de código:

affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd

Neste exemplo, o pod só pode rodar em nós rotulados com disktype=ssd.

2. PreferredDuringSchedulingIgnoredDuringExecution

preferredDuringSchedulingIgnoredDuringExecution define regras de afinidade soft que influenciam as decisões de agendamento sem torná-las obrigatórias. O scheduler tenta posicionar os pods em nós que correspondam às condições preferidas, mas ainda pode agendar o pod em outros nós, se necessário.

As regras de afinidade preferred usam um sistema de pesos. Cada preferência recebe um valor de peso entre 1 e 100. Os nós que correspondem a preferências com pesos mais altos recebem pontuações maiores durante o agendamento, aumentando a probabilidade de serem selecionados.

Essa abordagem é útil quando as preferências de posicionamento melhoram o desempenho ou a eficiência de custos, mas não são estritamente obrigatórias. Por exemplo, você pode preferir que os workloads rodem em nós com SSD ou dentro de uma determinada zona para reduzir a latência, sem impedir o agendamento em outro lugar em caso de escassez de recursos.

Exemplo de código:

affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd

Neste exemplo, o Kubernetes prefere nós rotulados com disktype=ssd, mas o pod ainda pode rodar em outros nós caso não haja nós com SSD disponíveis.

Casos de uso comuns de node affinity

Rodar workloads de GPU em nós com GPU

O node affinity é usado ao executar workloads de GPU em um cluster Kubernetes. Ao rotular os nós habilitados para GPU com uma chave como gpu=true, você garante que os pods que exigem recursos de GPU sejam agendados apenas em hardware compatível. Isso evita disputa por recursos entre workloads que dependem de GPU.

A afinidade soft pode ser usada se rodar em nós de CPU como alternativa for aceitável em cenários não críticos.

Agendar bancos de dados em nós com SSD

Bancos de dados geralmente exigem alto desempenho de I/O, algo que nós com SSD podem oferecer. Ao rotular os nós com disktype=ssd e definir node affinity required nos pods de banco de dados, você garante alto desempenho de armazenamento e menor latência para workloads stateful.

À medida que novos nós SSD são adicionados e rotulados, os pods de banco de dados se tornam elegíveis para agendamento neles.

Manter workloads em uma zona de disponibilidade específica

Executar workloads em uma zona de disponibilidade específica pode reduzir a latência, melhorar a tolerância a falhas ou atender a requisitos regulatórios. Ao rotular os nós com um identificador de zona, como zone=us-west1-b, e especificar o node affinity na spec dos pods, você controla a distribuição dos pods entre as zonas.

Usando afinidade preferred, você orienta o scheduler a posicionar os pods na zona desejada, permitindo recorrer a outras zonas caso os recursos estejam limitados.

Separar workloads de produção e de desenvolvimento

Separar ambientes de produção e de desenvolvimento em um cluster compartilhado é um caso de uso comum do node affinity. Ao rotular os nós como env=prod ou env=dev, você aplica políticas de posicionamento que impedem que workloads de desenvolvimento rodem em nós de produção, e vice-versa.

Com node affinity required, você impõe uma separação rígida, enquanto a afinidade preferred oferece flexibilidade em situações de recursos limitados.

Node affinity vs. node selector vs. pod affinity

Node affinity, node selectors e pod affinity são mecanismos de agendamento do Kubernetes, mas resolvem problemas de posicionamento diferentes e oferecem níveis distintos de flexibilidade.

O node selector é a opção mais simples. Ele permite que um pod rode apenas em nós com labels específicos. A configuração é direta, usando correspondências exatas de chave-valor, como disktype=ssd. No entanto, o nodeSelector suporta apenas verificações simples de igualdade e não consegue expressar condições mais avançadas, como múltiplos valores ou regras de exclusão.

O node affinity amplia as capacidades do nodeSelector ao suportar operadores de correspondência avançados, como In, NotIn, Exists e DoesNotExist. Ele também suporta regras de agendamento tanto required quanto preferred, dando aos administradores mais controle sobre o posicionamento dos pods. O node affinity costuma ser usado quando os workloads precisam ser direcionados a nós com hardware, regiões ou funções operacionais específicas.

O pod affinity funciona de forma diferente porque foca nas relações entre pods, e não nos labels dos nós. Ele permite que pods sejam agendados perto de outros pods com labels específicos, geralmente no mesmo nó ou na mesma zona de disponibilidade. Isso é útil para reduzir a latência de rede entre serviços fortemente acoplados. O Kubernetes também suporta pod anti-affinity, que distribui os pods para melhorar a disponibilidade e a tolerância a falhas.

A tabela a seguir resume as principais diferenças:

Recurso Node Selector Node Affinity Pod Affinity
Alvo Labels de nós Labels de nós Outros pods
Complexidade Simples Avançada Avançada
Operadores suportados Apenas igualdade Múltiplos operadores Seletores de labels
Regras hard e soft Não Sim Sim
Principal caso de uso Seleção básica de nós Posicionamento flexível em nós Co-localização ou separação de pods

Dicas de especialista para usar node affinity com eficiência

1. Padronize os labels dos nós antes de escrever regras de afinidade

O node affinity depende dos labels dos nós, então uma rotulagem inconsistente pode causar falhas de agendamento ou posicionamento imprevisível dos pods. Defina uma estratégia clara de rotulagem antes de criar políticas de afinidade. Use convenções de nomenclatura consistentes para labels como ambiente, tipo de hardware, região, função do workload ou classe de armazenamento.

Por exemplo, padronize labels como env=prod, disktype=ssd ou workload=batch. Evite criar múltiplos labels que representem o mesmo conceito, como gpu=true e accelerator=gpu.

Automatize o gerenciamento de labels sempre que possível. Provedores de nuvem e ferramentas de provisionamento de clusters geralmente suportam rotulagem automática para tipos de instância, zonas e pools de nós. A automação reduz erros de configuração manual e garante que novos nós sejam compatíveis com as políticas de afinidade existentes.

2. Prefira regras soft, a menos que o posicionamento seja obrigatório

Regras de afinidade hard podem tornar workloads não agendáveis se não houver nós compatíveis disponíveis. O uso excessivo de requiredDuringSchedulingIgnoredDuringExecution pode reduzir a flexibilidade do cluster durante eventos de escalonamento, janelas de manutenção ou falhas de nós.

Regras de afinidade preferred proporcionam um comportamento de agendamento mais resiliente. Elas permitem que o Kubernetes priorize os nós ideais, mas ainda posicione workloads em outros nós quando necessário.

Use afinidade hard apenas quando o posicionamento for obrigatório, como para aplicações que dependem de GPU, workloads com restrições de licenciamento, sistemas sensíveis a compliance ou aplicações que exigem recursos de hardware específicos.

3. Alinhe o node affinity com o autoscaling de nós

O node affinity deve estar alinhado com as políticas de autoscaling do cluster. Se os workloads exigem nós com labels específicos, o autoscaler precisa conseguir provisionar grupos de nós compatíveis. Caso contrário, os pods podem ficar presos em estado Pending mesmo com o autoscaling habilitado.

Por exemplo, workloads de GPU devem ser direcionados a pools de nós dedicados a instâncias com GPU, enquanto workloads intensivos em armazenamento devem se alinhar a grupos de nós com SSD.

Verifique se os limites do autoscaler suportam o crescimento esperado dos workloads. Se o autoscaler não conseguir criar nós compatíveis adicionais por causa de limites de cota ou restrições de configuração, as regras de afinidade podem bloquear os deployments.

4. Use a afinidade junto com o rightsizing dos workloads

O node affinity é mais eficaz quando os workloads estão dimensionados corretamente. Requests de CPU ou memória superprovisionados podem limitar as opções de agendamento, mesmo que nós adequados correspondam às regras de afinidade.

Por exemplo, um pod com requisitos rígidos de afinidade e requests de memória excessivos pode ficar sem agendamento mesmo com nós compatíveis disponíveis.

Revise os requests e limits de recursos dos workloads junto com as políticas de afinidade. Ferramentas de monitoramento e métricas do Kubernetes podem ajudar a identificar workloads que consomem consistentemente menos recursos do que o solicitado.

5. Revise as políticas de afinidade conforme os workloads evoluem

Os requisitos de infraestrutura e das aplicações mudam com o tempo, então as políticas de node affinity devem ser revisadas regularmente. Labels que já foram relevantes podem ficar desatualizados após upgrades de cluster, migrações ou mudanças de arquitetura.

Revisões periódicas ajudam a identificar restrições desnecessárias, labels sem uso ou políticas de agendamento que reduzem a eficiência do cluster.

As revisões operacionais devem incluir tanto as equipes de plataforma quanto as de aplicação, para garantir que as regras de afinidade continuem correspondendo aos requisitos dos workloads sem adicionar complexidade desnecessária ao agendamento.

Otimize o posicionamento de nós e a eficiência de recursos com o PerfectScale

O node affinity dá a você controle sobre onde os workloads rodam, mas até pods bem posicionados podem desperdiçar capacidade ou acionar escalonamento desnecessário de nós se seus requests e limits de recursos estiverem desajustados. Contêineres superprovisionados forçam o autoscaler a criar mais nós do que o necessário, contêineres subprovisionados causam OOM kills e evictions justamente nos nós que as regras de afinidade selecionaram com cuidado, e um bin-packing ineficiente deixa nós rotulados subutilizados. O PerfectScale aumenta a eficiência do Kubernetes aplicando right-sizing autônomo aos workloads e oferecendo visibilidade profunda no nível dos nós, para que suas políticas de afinidade posicionem os pods em nós já configurados para máxima eficiência.

Principais recursos do PerfectScale:

  • Right-sizing autônomo de workloads: analisa continuamente os workloads e ajusta os requests e limits de CPU e memória com base no uso real, garantindo que os pods agendados por regras de afinidade usem os recursos com eficiência.
  • Visibilidade e otimização no nível dos nós: oferece visibilidade abrangente dos seus nós e pools de nós, valida node affinities e taints em relação aos padrões reais de agendamento dos workloads e ajuda você a selecionar os tipos de nó ideais para cada workload.
  • Correções proativas de configuração: identifica erros de configuração — como CPU Request Not Set, Memory Request Not Set e Memory Limit Not Set — que causam evictions, over-commitment de nós e agendamento ineficiente nos seus nós cuidadosamente rotulados.
  • Eficiência de autoscaling: ajusta as configurações dos workloads para que autoscalers como Karpenter e Cluster Autoscaler provisionem os tipos e tamanhos certos de nós, mantendo o posicionamento orientado por afinidade previsível e econômico.

Quer garantir que seu agendamento orientado por afinidade posicione os pods em nós eficientes e bem dimensionados? Saiba mais sobre o PerfectScale.

Perguntas frequentes

Qual é a diferença entre node affinity hard e soft? Regras hard (requiredDuringSchedulingIgnoredDuringExecution) precisam ser satisfeitas, ou o pod permanece em Pending. Regras soft (preferredDuringSchedulingIgnoredDuringExecution) são uma preferência: o scheduler tenta respeitá-las, mas posiciona o pod em outro lugar se necessário.

Qual é a diferença entre node affinity e nodeSelector? O nodeSelector suporta apenas regras simples de correspondência exata de labels. O node affinity suporta operadores mais ricos (In, NotIn, Exists, DoesNotExist), além de lógica de agendamento tanto required quanto preferred.

Qual é a diferença entre node affinity e pod affinity? O node affinity relaciona pods aos labels dos nós. O pod affinity (e o anti-affinity) relaciona pods ao posicionamento de outros pods, normalmente para co-localizar ou distribuir workloads relacionados.

Por que meu pod está preso em Pending com node affinity configurado? Geralmente porque nenhum nó corresponde a uma regra hard (required): verifique os labels dos nós, confirme se o autoscaler consegue provisionar nós compatíveis e confira se os requests de recursos do pod não estão superdimensionados para os nós compatíveis.

Quando devo usar regras hard em vez de soft? Apenas quando o posicionamento é realmente obrigatório: workloads que dependem de GPU, restrições de licenciamento ou requisitos de compliance/residência de dados. Caso contrário, prefira regras soft para manter o agendamento flexível.

Alterar os labels de um nó afeta pods que já estão em execução? Não. Como as regras são "IgnoredDuringExecution", um pod em execução não é removido se os labels do nó mudarem depois que ele foi agendado.