PerfectScale
Guía definitiva de Node Affinity: ejemplos, casos de uso y consejos pro
Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.
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 pageTLDR: La node affinity te permite restringir en qué nodos puede ejecutarse un pod según las etiquetas de los nodos, mediante reglas estrictas (requiredDuringSchedulingIgnoredDuringExecution) o flexibles (preferredDuringSchedulingIgnoredDuringExecution). Es más expresiva que nodeSelector y se usa habitualmente para dirigir workloads a nodos con GPU o SSD, mantenerlos en una zona específica o separar producción de desarrollo. Estandariza las etiquetas de los nodos, prefiere las reglas flexibles salvo que la ubicación sea obligatoria y alinea la afinidad con el autoescalado y el dimensionamiento de los workloads para evitar que los pods queden atascados en estado Pending.
En este artículo:
¿Qué es la node affinity en Kubernetes?
La node affinity (afinidad de nodos) en Kubernetes es un conjunto de reglas que se usa para restringir en qué nodos se puede programar un pod, con base en las etiquetas asignadas a los nodos. Permite una lógica de programación más expresiva y compleja que nodeSelector, ya que admite tanto reglas flexibles como reglas estrictas para ubicar pods en hardware específico y etiquetado, como SSD o GPU.
Esta funcionalidad resulta especialmente útil en clústeres de Kubernetes multi-tenant, híbridos o heterogéneos, donde los workloads pueden tener requisitos distintos de hardware o de ubicación. La node affinity te permite optimizar el uso de recursos, aislar workloads sensibles y mejorar el rendimiento de las aplicaciones al asignar cada workload a los nodos con las características más adecuadas.
Tipos principales de node affinity:
- Reglas estrictas (requiredDuringSchedulingIgnoredDuringExecution): el scheduler debe encontrar un nodo que cumpla las condiciones para ubicar el pod; de lo contrario, este permanece en estado Pending.
- Reglas flexibles (preferredDuringSchedulingIgnoredDuringExecution): el scheduler intenta encontrar un nodo que cumpla las condiciones, pero si no hay ninguno disponible, programa el pod en otro lugar de todos modos.
Ejemplo de uso (YAML):
spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssdEste artículo forma parte de una serie sobre Kubernetes scheduling.
Cómo funciona la node affinity en Kubernetes
Estos son los elementos técnicos clave detrás de la node affinity.
Etiquetas de nodos
Las etiquetas de nodos son pares clave-valor que se asignan a los nodos de Kubernetes para describir sus atributos. Las etiquetas son arbitrarias y pueden representar características como el tipo de instancia, la región, la zona de disponibilidad o metadatos personalizados relevantes para la programación de workloads. Por ejemplo, puedes etiquetar nodos con disktype=ssd o gpu=true para identificar aquellos con almacenamiento SSD o aceleración por GPU.
Las etiquetas las definen los administradores del clúster o scripts de automatización, ya sea al agregar nodos al clúster o de forma dinámica a medida que la infraestructura cambia. Un etiquetado coherente y con significado claro es esencial para que la node affinity funcione bien, ya que las reglas de afinidad dependen de estas etiquetas para seleccionar los nodos adecuados donde ubicar los pods. Un etiquetado correcto garantiza que el scheduler pueda interpretar y aplicar tus políticas de ubicación como corresponde.
Operadores de node affinity
Las reglas de node affinity usan operadores para definir cómo deben coincidir los pods con las etiquetas de los nodos. Los operadores más comunes son In, NotIn, Exists y DoesNotExist. Los operadores In y NotIn permiten especificar valores aceptables o inaceptables para una etiqueta determinada, mientras que Exists y DoesNotExist verifican la presencia o ausencia de una clave de etiqueta, sin importar su valor.
Estos operadores ofrecen flexibilidad para expresar requisitos de programación complejos. Por ejemplo, puedes exigir que los pods se ejecuten solo en nodos donde environment=production o evitar nodos con dedicated=backup. Al combinar distintos operadores y selectores de etiquetas, se puede afinar la ubicación de los pods para cumplir los requisitos de los workloads y las políticas de la organización.
Comportamiento del scheduler
El scheduler de Kubernetes evalúa las reglas de node affinity al decidir dónde ubicar un pod. Compara las etiquetas de los nodos disponibles con los criterios de afinidad definidos en la especificación del pod. Si un nodo cumple las reglas de afinidad requeridas, pasa a ser elegible para programar el pod; en caso contrario, el pod queda sin programar hasta que haya un nodo adecuado disponible.
Existen dos tipos de node affinity: requerida (estricta) y preferida (flexible). Las reglas requeridas deben cumplirse para que el pod se programe, mientras que las preferidas influyen en la decisión del scheduler pero no impiden la programación si no hay nodos preferidos disponibles. Esta distinción permite estrategias de ubicación tanto estrictas como flexibles, equilibrando las necesidades operativas con la disponibilidad de recursos.
Sintaxis YAML de la node affinity: reglas estrictas vs. flexibles
1. RequiredDuringSchedulingIgnoredDuringExecution
requiredDuringSchedulingIgnoredDuringExecution define reglas estrictas de node affinity que deben cumplirse antes de que un pod pueda programarse en un nodo. El scheduler solo considera nodos cuyas etiquetas coinciden con todas las condiciones especificadas. Si no hay ningún nodo compatible disponible, el pod permanece en estado Pending hasta que aparezca uno adecuado.
Este tipo de afinidad se usa habitualmente para workloads con requisitos estrictos de infraestructura. Por ejemplo, una aplicación de machine learning puede requerir nodos con GPU, o un workload sujeto a normativas de cumplimiento puede necesitar ejecutarse únicamente en una región o zona de disponibilidad específica.
La parte IgnoredDuringExecution significa que Kubernetes no desaloja el pod si las etiquetas del nodo cambian después de la programación. Si una etiqueta del nodo se elimina o modifica más adelante, el pod en ejecución sigue operando en ese nodo, a menos que otro mecanismo desencadene una reprogramación.
Ejemplo de código:
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssdEn este ejemplo, el pod solo puede ejecutarse en nodos etiquetados con disktype=ssd.
2. PreferredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution define reglas de afinidad flexibles que influyen en las decisiones de programación sin hacerlas obligatorias. El scheduler intenta ubicar los pods en nodos que cumplan las condiciones preferidas, pero puede programar el pod en otros nodos si es necesario.
Las reglas de afinidad preferida usan un sistema de ponderación. A cada preferencia se le asigna un peso entre 1 y 100. Los nodos que coinciden con preferencias de mayor peso obtienen puntuaciones más altas durante la programación, lo que aumenta su probabilidad de ser seleccionados.
Este enfoque es útil cuando las preferencias de ubicación mejoran el rendimiento o la eficiencia de costos, pero no son estrictamente obligatorias. Por ejemplo, puedes preferir que los workloads se ejecuten en nodos con SSD o dentro de cierta zona para reducir la latencia, permitiendo de todos modos la programación en otro lugar cuando escaseen los recursos.
Ejemplo de código:
affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 50 preference: matchExpressions: - key: disktype operator: In values: - ssdEn este ejemplo, Kubernetes prefiere los nodos etiquetados con disktype=ssd, pero el pod puede ejecutarse igualmente en otros nodos si no hay disponibles nodos con SSD.
Casos de uso comunes de la node affinity
Ejecutar workloads de GPU en nodos con GPU
La node affinity se usa al ejecutar workloads de GPU en un clúster de Kubernetes. Al etiquetar los nodos con GPU habilitada con una clave como gpu=true, puedes asegurarte de que los pods que requieren recursos de GPU se programen solo en hardware compatible. Esto evita la contención de recursos para los workloads que dependen de GPU.
Se puede usar afinidad flexible si en escenarios no críticos es aceptable recurrir a nodos de CPU como alternativa.
Programar bases de datos en nodos con SSD
Las bases de datos suelen requerir un alto rendimiento de E/S, que los nodos con SSD pueden ofrecer. Al etiquetar los nodos con disktype=ssd y establecer node affinity requerida en los pods de bases de datos, garantizas un alto rendimiento de almacenamiento y menor latencia para los workloads con estado.
A medida que se agregan y etiquetan nuevos nodos con SSD, los pods de bases de datos pasan a ser elegibles para programarse en ellos.
Mantener workloads en una zona de disponibilidad específica
Ejecutar workloads en una zona de disponibilidad específica puede reducir la latencia, mejorar la tolerancia a fallas o cumplir requisitos regulatorios. Al etiquetar los nodos con un identificador de zona como zone=us-west1-b y especificar node affinity en las especificaciones de los pods, puedes controlar la distribución de los pods entre zonas.
Con la afinidad preferida, puedes orientar al scheduler para que ubique los pods en la zona deseada, pero permitir que recurra a otras zonas si los recursos son limitados.
Separar workloads de producción y desarrollo
Separar los entornos de producción y desarrollo en un clúster compartido es un caso de uso común de la node affinity. Al etiquetar los nodos como env=prod o env=dev, puedes aplicar políticas de ubicación que impidan que los workloads de desarrollo se ejecuten en nodos de producción, y viceversa.
Con la node affinity requerida impones una separación estricta, mientras que la afinidad preferida permite flexibilidad en situaciones de recursos limitados.
Node affinity vs. node selector vs. pod affinity
La node affinity, los node selectors y la pod affinity son mecanismos de programación de Kubernetes, pero resuelven problemas de ubicación distintos y ofrecen diferentes niveles de flexibilidad.
Un node selector es la opción más simple. Permite que un pod se ejecute únicamente en nodos con etiquetas específicas. Su configuración es sencilla y usa coincidencias exactas de clave-valor, como disktype=ssd. Sin embargo, nodeSelector solo admite comparaciones simples de igualdad y no puede expresar condiciones más avanzadas, como múltiples valores o reglas de exclusión.
La node affinity amplía las capacidades de nodeSelector al admitir operadores de coincidencia avanzados como In, NotIn, Exists y DoesNotExist. También admite reglas de programación tanto requeridas como preferidas, lo que da a los administradores más control sobre la ubicación de los pods. La node affinity se usa habitualmente cuando los workloads deben dirigirse a nodos con hardware, regiones o roles operativos específicos.
La pod affinity funciona de manera diferente, porque se centra en las relaciones entre pods y no en las etiquetas de los nodos. Permite programar pods cerca de otros pods con etiquetas específicas, normalmente en el mismo nodo o zona de disponibilidad. Esto es útil para reducir la latencia de red entre servicios estrechamente acoplados. Kubernetes también admite la pod anti-affinity, que distribuye los pods de forma separada para mejorar la disponibilidad y la tolerancia a fallas.
La siguiente tabla resume las principales diferencias:
| Característica | Node Selector | Node Affinity | Pod Affinity |
|---|---|---|---|
| Objetivo | Etiquetas de nodos | Etiquetas de nodos | Otros pods |
| Complejidad | Simple | Avanzada | Avanzada |
| Operadores admitidos | Solo igualdad | Múltiples operadores | Selectores de etiquetas |
| Reglas estrictas y flexibles | No | Sí | Sí |
| Caso de uso principal | Selección básica de nodos | Ubicación flexible en nodos | Colocación conjunta o separación de pods |
Consejos pro para usar la node affinity de forma eficaz
1. Estandariza las etiquetas de los nodos antes de escribir reglas de afinidad
La node affinity depende de las etiquetas de los nodos, por lo que un etiquetado inconsistente puede provocar fallas de programación o una ubicación impredecible de los pods. Define una estrategia de etiquetado clara antes de crear políticas de afinidad. Usa convenciones de nomenclatura coherentes para etiquetas como entorno, tipo de hardware, región, rol del workload o clase de almacenamiento.
Por ejemplo, estandariza etiquetas como env=prod, disktype=ssd o workload=batch. Evita crear múltiples etiquetas que representen el mismo concepto, como gpu=true y accelerator=gpu.
Automatiza la gestión de etiquetas siempre que sea posible. Los proveedores de nube y las herramientas de aprovisionamiento de clústeres suelen admitir el etiquetado automático de tipos de instancia, zonas y grupos de nodos. La automatización reduce los errores de configuración manual y garantiza que los nodos nuevos sean compatibles con las políticas de afinidad existentes.
2. Prefiere las reglas flexibles salvo que la ubicación sea obligatoria
Las reglas de afinidad estrictas pueden hacer que los workloads queden sin programar si no hay nodos compatibles disponibles. Abusar de requiredDuringSchedulingIgnoredDuringExecution puede reducir la flexibilidad del clúster durante eventos de escalado, ventanas de mantenimiento o fallas de nodos.
Las reglas de afinidad preferida ofrecen un comportamiento de programación más resiliente. Permiten que Kubernetes priorice los nodos ideales sin dejar de ubicar los workloads en otro lugar cuando sea necesario.
Usa la afinidad estricta solo cuando la ubicación sea obligatoria, como en aplicaciones que dependen de GPU, workloads con restricciones de licenciamiento, sistemas sujetos a normativas de cumplimiento o aplicaciones que requieren características de hardware específicas.
3. Alinea la node affinity con el autoescalado de nodos
La node affinity debe estar alineada con las políticas de autoescalado del clúster. Si los workloads requieren nodos con etiquetas específicas, el autoscaler debe poder aprovisionar grupos de nodos compatibles. De lo contrario, los pods pueden quedar atascados en estado Pending incluso con el autoescalado habilitado.
Por ejemplo, los workloads de GPU deben dirigirse a grupos de nodos dedicados a instancias con GPU, mientras que los workloads con uso intensivo de almacenamiento deben alinearse con grupos de nodos respaldados por SSD.
Verifica que los límites del autoscaler soporten el crecimiento esperado de los workloads. Si el autoscaler no puede crear nodos compatibles adicionales debido a límites de cuota o restricciones de configuración, las reglas de afinidad pueden bloquear los despliegues.
4. Combina la afinidad con el right-sizing de los workloads
La node affinity es más eficaz cuando los workloads están correctamente dimensionados. Las solicitudes de CPU o memoria sobredimensionadas pueden limitar las opciones de programación, incluso si hay nodos adecuados que cumplen las reglas de afinidad.
Por ejemplo, un pod con requisitos de afinidad estrictos y solicitudes de memoria excesivas puede quedar sin programar aunque existan nodos compatibles.
Revisa las solicitudes y límites de recursos de los workloads junto con las políticas de afinidad. Las herramientas de monitoreo y las métricas de Kubernetes pueden ayudar a identificar workloads que consumen sistemáticamente menos recursos de los solicitados.
5. Revisa las políticas de afinidad a medida que evolucionan los workloads
Los requisitos de infraestructura y de las aplicaciones cambian con el tiempo, por lo que las políticas de node affinity deben revisarse con regularidad. Etiquetas que en su momento fueron significativas pueden quedar obsoletas tras actualizaciones del clúster, migraciones o cambios de arquitectura.
Las revisiones periódicas ayudan a identificar restricciones innecesarias, etiquetas sin uso o políticas de programación que reducen la eficiencia del clúster.
Las revisiones operativas deben incluir tanto a los equipos de plataforma como a los de aplicaciones, para garantizar que las reglas de afinidad sigan correspondiéndose con los requisitos de los workloads sin añadir una complejidad de programación innecesaria.
Optimiza la ubicación de nodos y la eficiencia de recursos con PerfectScale
La node affinity te da control sobre dónde se ejecutan los workloads, pero incluso los pods bien ubicados pueden desperdiciar capacidad o provocar un escalado de nodos innecesario si sus solicitudes y límites de recursos están mal calibrados. Los contenedores sobredimensionados obligan al autoscaler a levantar más nodos de los necesarios, los subdimensionados provocan OOM kills y desalojos justo en los nodos que las reglas de afinidad seleccionaron con tanto cuidado, y un bin-packing ineficiente deja los nodos etiquetados subutilizados. PerfectScale mejora la eficiencia de Kubernetes al aplicar right-sizing de forma autónoma a los workloads y ofrecer una visibilidad profunda a nivel de nodo, de modo que tus políticas de afinidad ubiquen los pods en nodos ya configurados para la máxima eficiencia.
Capacidades clave de PerfectScale:
- Right-sizing autónomo de workloads: analiza los workloads de forma continua y ajusta las solicitudes y límites de CPU y memoria según el uso real, garantizando que los pods programados mediante reglas de afinidad usen los recursos de manera eficiente.
- Visibilidad y optimización a nivel de nodo: ofrece una visibilidad integral de tus nodos y grupos de nodos, valida las node affinities y los taints frente a los patrones reales de programación de los workloads y te ayuda a seleccionar los tipos de nodo óptimos para cada workload.
- Corrección proactiva de configuraciones: identifica errores de configuración —como CPU Request Not Set, Memory Request Not Set y Memory Limit Not Set— que causan desalojos, sobreasignación de nodos y una programación ineficiente en tus nodos cuidadosamente etiquetados.
- Eficiencia en el autoescalado: afina las configuraciones de los workloads para que autoscalers como Karpenter y Cluster Autoscaler aprovisionen los tipos y tamaños de nodo correctos, manteniendo la ubicación basada en afinidad predecible y rentable.
¿Quieres asegurarte de que tu programación basada en afinidad termine en nodos eficientes y correctamente dimensionados? Conoce más sobre PerfectScale.
Preguntas frecuentes
¿Cuál es la diferencia entre la node affinity estricta y la flexible?
Las reglas estrictas (requiredDuringSchedulingIgnoredDuringExecution) deben cumplirse o el pod permanece en Pending. Las reglas flexibles (preferredDuringSchedulingIgnoredDuringExecution) son una preferencia: el scheduler intenta respetarlas, pero ubicará el pod en otro lugar si es necesario.
¿En qué se diferencia la node affinity de nodeSelector?
nodeSelector solo admite reglas simples de coincidencia exacta de etiquetas. La node affinity admite operadores más completos (In, NotIn, Exists, DoesNotExist), además de lógica de programación tanto requerida como preferida.
¿En qué se diferencia la node affinity de la pod affinity? La node affinity asocia los pods a las etiquetas de los nodos. La pod affinity (y la anti-affinity) asocia los pods a la ubicación de otros pods, normalmente para colocar juntos o distribuir workloads relacionados.
¿Por qué mi pod queda atascado en Pending con node affinity configurada?
Generalmente porque ningún nodo cumple una regla estricta (required): revisa las etiquetas de los nodos, verifica que el autoscaler pueda aprovisionar nodos compatibles y confirma que las solicitudes de recursos del pod no sean excesivas para los nodos que coinciden.
¿Cuándo debo usar reglas estrictas en lugar de flexibles? Solo cuando la ubicación sea realmente obligatoria: workloads que dependen de GPU, restricciones de licenciamiento o requisitos de cumplimiento y residencia de datos. En los demás casos, prefiere las reglas flexibles para mantener la programación flexible.
¿Cambiar las etiquetas de un nodo afecta a los pods que ya están en ejecución? No. Como las reglas son "IgnoredDuringExecution", un pod en ejecución no se desaloja si las etiquetas del nodo cambian después de haber sido programado.