Skip to content

Kubernetes Scheduling, Preemption, and Eviction

Versiones compatibles: Kubernetes 1.32 - 1.34 Última actualización: February 22, 2026

En Kubernetes, scheduling (programación) es el proceso de colocar pods en nodes apropiados. Preemption es el proceso de eliminar pods de menor prioridad para dejar espacio a pods de mayor prioridad, y eviction es el proceso de mover pods de forma segura cuando ocurren problemas en los nodes. En este capítulo, aprenderemos sobre los mecanismos de scheduling de Kubernetes, la selección de nodes, preemption, eviction y los métodos de optimización de scheduling en Amazon EKS.

Lab Environment Setup

Para seguir los ejemplos de este documento, necesitas las siguientes herramientas y entorno:

Required Tools

  • kubectl v1.34 o superior
  • Un cluster Kubernetes funcional (EKS, minikube, kind, etc.)
  • Un cluster con múltiples nodes (para pruebas de scheduling)

Scheduling Example Setup

bash
# Create namespace
kubectl create namespace scheduling-demo

# Add labels to nodes (if you have multiple nodes)
kubectl label nodes <node-name> disktype=ssd
kubectl label nodes <node-name> gpu=true

# Create a pod using node affinity
kubectl -n scheduling-demo apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: nginx-ssd
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
  containers:
  - name: nginx
    image: nginx
EOF

# Create priority class
kubectl apply -f - <<EOF
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for critical service pods only."
EOF

# Create Pod Disruption Budget (PDB)
kubectl -n scheduling-demo apply -f - <<EOF
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: nginx-pdb
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: nginx
EOF

Kubernetes Scheduling Architecture

Scheduling Concept Comparison

ConceptPurposeUse CasesKubernetes Version
Node SelectorPlace pods on nodes with specific labelsSimple node selectionAll versions
Node AffinityDefine complex node selection rulesAdvanced node selection1.6+
Pod AffinityPlace pods close to other podsCo-locating related services1.6+
Pod Anti-AffinityPlace pods away from other podsEnsuring high availability1.6+
Taints and TolerationsAllow only specific pods on nodesDedicated nodes, node isolation1.6+
Topology Spread ConstraintsSpread pods across topology domainsDistribution across availability zones1.16+ (GA in 1.19)
Priority and PreemptionPrioritize important workloadsCritical service guarantees1.8+ (GA in 1.11)
Pod Disruption BudgetLimit simultaneously disrupted podsEnsuring high availability1.4+ (GA in 1.21)

Basic Scheduling Concepts

Concepto clave: El Kubernetes scheduler es un componente del control plane que selecciona el node óptimo para ejecutar pods, operando en dos fases: filtering y scoring.

Scheduling Process

  1. Filtering Phase (Predicates)

    • Identifica un conjunto adecuado de nodes que pueden ejecutar el pod
    • Considera requisitos de recursos, node selectors, reglas de affinity, taints/tolerations, etc.
    • Excluye un node si no se cumple alguna condición
  2. Scoring Phase (Priorities)

    • Asigna puntuaciones a los nodes que pasaron el filtering
    • Considera la utilización de recursos, distribución de pods, preferencias de affinity, etc.
    • Selecciona el node con la puntuación más alta
  3. Binding Phase

    • Asigna el pod al node seleccionado
    • Actualiza la información de binding en el API server

Table of Contents

  1. Scheduling Overview
  2. How the Scheduler Works
  3. Node Selection
  4. Pod Affinity and Anti-Affinity
  5. Taints and Tolerations
  6. Node Affinity
  7. Pod Priority and Preemption
  8. Pod Eviction
  9. Pod Disruption Budget (PDB)
  10. Node Pressure Eviction
  11. TopologySpreadConstraints
  12. Pod Deletion Cost
  13. Descheduler
  14. Scheduling Optimization in Amazon EKS
  15. Scheduling Best Practices
  16. Conclusion

Scheduling Overview

El Kubernetes scheduler es un componente del control plane que coloca pods en nodes apropiados. El scheduler considera diversos factores para determinar el node óptimo donde colocar pods:

  1. Resource Requirements: CPU, memoria y otros recursos solicitados por el pod
  2. Hardware/Software/Policy Constraints: Node selectors, node affinity, taints, etc.
  3. Affinity/Anti-Affinity Specifications: Relaciones de ubicación con otros pods
  4. Data Locality: Colocar pods cerca de los datos
  5. Inter-Workload Interference: Minimizar la interferencia entre distintos workloads
  6. Deadlines: Considerar workloads con restricciones de tiempo

Scheduling Process

El proceso de scheduling se divide ampliamente en dos fases:

  1. Filtering: Identifica un conjunto de nodes que pueden ejecutar el pod

    • Comprueba si se cumplen los requisitos de recursos
    • Comprueba constraints como node selectors, affinity, taints
  2. Scoring: Puntúa los nodes filtrados para seleccionar el node óptimo

    • Equilibrio de utilización de recursos
    • Affinity/anti-affinity entre pods
    • Localidad de datos
    • Taints/tolerations

How the Scheduler Works

El Kubernetes scheduler opera mediante el siguiente proceso:

  1. Pod Queue Watching: El scheduler observa el API server en busca de pods no programados.
  2. Node Filtering: Identifica un conjunto de nodes que pueden ejecutar el pod.
  3. Node Scoring: Puntúa los nodes filtrados.
  4. Node Selection: Selecciona el node con la puntuación más alta.
  5. Binding: Vincula el pod al node seleccionado.

Scheduling Plugins

El Kubernetes scheduler está diseñado para ser extensible mediante una arquitectura de plugins. Diversos plugins operan en distintas etapas del proceso de scheduling:

  1. Filter Plugins: Filtran los nodes donde el pod no puede ejecutarse

    • NodeResourcesFit: Comprueba la capacidad de recursos del node
    • NodeName: Comprueba el campo nodeName del pod
    • NodeUnschedulable: Comprueba la schedulability del node
    • TaintToleration: Comprueba taints y tolerations
  2. Score Plugins: Asignan puntuaciones a los nodes

    • NodeResourcesBalancedAllocation: Considera el equilibrio de uso de recursos
    • ImageLocality: Considera la localidad de la imagen
    • InterPodAffinity: Considera la affinity entre pods
    • NodeAffinity: Considera la node affinity

Multiple Schedulers

Kubernetes puede ejecutar múltiples schedulers simultáneamente. Esto permite implementar lógica de scheduling personalizada para workloads específicos.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: custom-scheduled-pod
spec:
  schedulerName: my-custom-scheduler
  containers:
  - name: container
    image: nginx

En el ejemplo anterior, el campo schedulerName especifica el scheduler que debe programar el pod.

Node Selection

Kubernetes proporciona varios mecanismos para colocar pods en nodes específicos.

Node Selector

Node selector es la forma más simple de restringir pods para que solo se coloquen en nodes con labels específicos.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  nodeSelector:
    gpu: "true"
  containers:
  - name: gpu-container
    image: nvidia/cuda

En el ejemplo anterior, el pod solo se coloca en nodes con el label gpu=true.

nodeName

Puedes usar el campo nodeName para colocar directamente un pod en un node específico. Este método omite el scheduler y generalmente no se recomienda.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: specific-node-pod
spec:
  nodeName: worker-node-1
  containers:
  - name: container
    image: nginx

En el ejemplo anterior, el pod se coloca directamente en el node llamado worker-node-1.

Pod Affinity and Anti-Affinity

Pod affinity y anti-affinity proporcionan formas de colocar pods según las relaciones entre pods.

Pod Affinity

Pod affinity hace que los pods se coloquen en el mismo node o dominio de topología que pods con labels específicos.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname
  containers:
  - name: frontend
    image: nginx

En el ejemplo anterior, el pod frontend se coloca en el mismo host que pods con el label app=cache.

Pod Anti-Affinity

Pod anti-affinity hace que los pods se coloquen en un node o dominio de topología diferente al de pods con labels específicos.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: frontend
  labels:
    app: frontend
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - frontend
        topologyKey: kubernetes.io/hostname
  containers:
  - name: frontend
    image: nginx

En el ejemplo anterior, el pod frontend se coloca en un host diferente al de otros pods con el label app=frontend. Esto es útil para distribuir instancias de la misma aplicación entre múltiples nodes para alta disponibilidad.

Affinity Types

Pod affinity y anti-affinity tienen dos tipos:

  1. requiredDuringSchedulingIgnoredDuringExecution: Requisito estricto que debe cumplirse durante el scheduling
  2. preferredDuringSchedulingIgnoredDuringExecution: Requisito flexible que se prefiere, pero no es obligatorio
yaml
# preferredDuringSchedulingIgnoredDuringExecution example
affinity:
  podAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname

En el ejemplo anterior, el campo weight indica el peso de esta preferencia. Cuando hay múltiples preferencias, las preferencias con mayor peso se consideran más importantes.

Taints and Tolerations

Taints y tolerations son mecanismos que permiten a los nodes rechazar pods específicos.

Taints

Los taints se aplican a nodes para restringir que pods se programen en ellos.

bash
# Add taint to node
kubectl taint nodes node1 key=value:NoSchedule

Hay tres efectos de taint:

  1. NoSchedule: Los pods sin tolerations no se programan en el node
  2. PreferNoSchedule: Se prefiere no programar pods sin tolerations en el node
  3. NoExecute: Los pods sin tolerations se evictan del node

Tolerations

Las tolerations se aplican a pods para permitir que se programen en nodes con taints.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"
  containers:
  - name: nginx
    image: nginx

En el ejemplo anterior, el pod se puede programar en nodes con el taint key=value:NoSchedule.

Use Cases

Casos de uso comunes para taints y tolerations:

  1. Dedicated Nodes: Designar nodes para ejecutar solo workloads específicos
  2. Special Hardware: Gestionar nodes con hardware especial como GPUs
  3. Node Maintenance: Evitar el scheduling de nuevos pods en nodes en mantenimiento
  4. Node Issues: Evictar pods de nodes con problemas

Default Taints

Kubernetes aplica taints predeterminados a algunos nodes:

  • node.kubernetes.io/not-ready: El node no está listo
  • node.kubernetes.io/unreachable: El node es inalcanzable
  • node.kubernetes.io/memory-pressure: El node tiene presión de memoria
  • node.kubernetes.io/disk-pressure: El node tiene presión de disco
  • node.kubernetes.io/pid-pressure: El node tiene presión de PID
  • node.kubernetes.io/network-unavailable: La red del node no está disponible
  • node.kubernetes.io/unschedulable: El node no es schedulable

Node Affinity

Node affinity proporciona una forma más expresiva de colocar pods en conjuntos específicos de nodes. Permite especificar condiciones más complejas que node selector.

Node Affinity Types

Node affinity tiene dos tipos:

  1. requiredDuringSchedulingIgnoredDuringExecution: Requisito estricto que debe cumplirse durante el scheduling
  2. preferredDuringSchedulingIgnoredDuringExecution: Requisito flexible que se prefiere, pero no es obligatorio
yaml
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: another-node-label-key
            operator: In
            values:
            - another-node-label-value
  containers:
  - name: with-node-affinity
    image: nginx

En el ejemplo anterior, el pod solo se coloca en nodes donde el label kubernetes.io/e2e-az-name es e2e-az1 o e2e-az2. Además, se coloca preferentemente en nodes con el label another-node-label-key=another-node-label-value.

Operators

Node affinity admite varios operadores:

  • In: El valor del label coincide con uno de los valores especificados
  • NotIn: El valor del label no coincide con los valores especificados
  • Exists: Existe un label con la key especificada
  • DoesNotExist: No existe un label con la key especificada
  • Gt: El valor del label es mayor que el valor especificado
  • Lt: El valor del label es menor que el valor especificado

Pod Priority and Preemption

Kubernetes proporciona características de pod priority y preemption para garantizar que workloads importantes puedan asegurar recursos del cluster.

PriorityClass

PriorityClass define la importancia relativa de los pods. Cuanto mayor sea el valor de prioridad, más importante es el pod.

yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for critical workloads."

En el ejemplo anterior, el campo value indica el valor de prioridad. Cuanto mayor sea el valor, mayor será la prioridad. Si el campo globalDefault se establece en true, esta priority class se aplica a pods sin una priority class especificada.

Applying PriorityClass to Pods

Para aplicar una priority class a un pod, usa el campo priorityClassName.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: high-priority-pod
spec:
  priorityClassName: high-priority
  containers:
  - name: container
    image: nginx

Preemption

Preemption es el proceso de eliminar pods de menor prioridad para programar pods de mayor prioridad. Cuando el scheduler no puede encontrar un node para programar un pod de mayor prioridad, hace preemption de pods de menor prioridad para asegurar recursos.

Proceso de preemption:

  1. El scheduler no puede encontrar un node para programar un pod de mayor prioridad
  2. El scheduler selecciona un node para eliminar pods de menor prioridad mediante preemption
  3. Envía una señal de terminación a los pods de menor prioridad en el node seleccionado
  4. Cuando los pods terminan de forma correcta, programa el pod de mayor prioridad en ese node

Preemption Considerations

Aspectos a considerar al usar preemption:

  1. Graceful Termination Period: Los pods preempted pasan por el proceso de terminación graceful durante el tiempo especificado en terminationGracePeriodSeconds
  2. PodDisruptionBudget: Preemption no respeta PodDisruptionBudget
  3. System Priority Classes: Kubernetes proporciona priority classes para componentes del sistema
    • system-cluster-critical: Pods críticos para la operación del cluster
    • system-node-critical: Pods críticos para la operación del node

Pod Eviction

Pod eviction es el proceso de mover pods de forma segura cuando ocurren problemas en los nodes. Eviction puede ocurrir por diversas razones.

Eviction Types

  1. Eviction by kube-controller-manager:

    • Cuando un node permanece en estado NotReady durante el período pod-eviction-timeout (predeterminado 5 minutos)
    • Cuando un node está en estado Unreachable
  2. Eviction by kubelet:

    • Escasez de recursos del node (memoria, disco, etc.)
    • Problemas de hardware
  3. Eviction by user:

    • Ejecutar el comando kubectl drain
    • Tareas de mantenimiento de nodes

kubelet Eviction Signals

kubelet monitorea las siguientes señales de eviction:

  1. memory.available: Memoria disponible
  2. nodefs.available: Espacio disponible en el sistema de archivos del node
  3. nodefs.inodesFree: Inodes disponibles en el sistema de archivos del node
  4. imagefs.available: Espacio disponible en el sistema de archivos de imágenes
  5. imagefs.inodesFree: Inodes disponibles en el sistema de archivos de imágenes
  6. pid.available: IDs de proceso disponibles

Se pueden establecer umbrales soft y hard para cada señal:

  • Soft Threshold: Evicta pods después del grace-period cuando se supera el umbral
  • Hard Threshold: Evicta pods inmediatamente cuando se supera el umbral
yaml
# kubelet configuration example
evictionHard:
  memory.available: "100Mi"
  nodefs.available: "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "15%"
evictionSoft:
  memory.available: "200Mi"
  nodefs.available: "15%"
evictionSoftGracePeriod:
  memory.available: "1m"
  nodefs.available: "2m"
evictionPressureTransitionPeriod: "30s"

Eviction Priority

kubelet evicta pods en el siguiente orden:

  1. Pods con clase QoS BestEffort
  2. Pods con clase QoS Burstable (comenzando por pods cuyo uso de recursos supera los requests)
  3. Pods con clase QoS Guaranteed (pods con requests y limits iguales)

Pod Disruption Budget (PDB)

Pod Disruption Budget (PDB) es una forma de mantener la disponibilidad de la aplicación durante disruptions voluntarias. PDB limita el número de pods que pueden interrumpirse simultáneamente.

PDB Definition

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: frontend-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: frontend

o

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: frontend-pdb
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: frontend

En los ejemplos anteriores:

  • minAvailable: Número mínimo de pods que siempre deben estar disponibles
  • maxUnavailable: Número máximo de pods que pueden no estar disponibles al mismo tiempo
  • selector: Label selector que selecciona los pods a los que se aplica el PDB

PDB Operation

  1. Cuando ocurren disruptions voluntarias como node drain, Kubernetes comprueba el PDB
  2. Si se cumplen las condiciones del PDB, continúa con la eviction del pod
  3. Si no se cumplen las condiciones del PDB, deniega la eviction del pod

PDB Best Practices

  1. Set PDB for all critical workloads: Establece PDB para todos los workloads que requieran alta disponibilidad
  2. Choose appropriate values: Selecciona valores de minAvailable o maxUnavailable apropiados para las características del workload
  3. Consider replica count: El valor del PDB debe ser menor que el número de replicas
  4. Regular testing: Prueba la operación del PDB mediante node drain y tareas similares

Node Pressure Eviction

Node pressure eviction es un mecanismo en el que los pods se evictan debido a escasez de recursos del node.

Node Condition Status

kubelet informa los siguientes estados de condición del node:

  1. MemoryPressure: El node tiene poca memoria
  2. DiskPressure: El node tiene poco espacio en disco
  3. PIDPressure: El node tiene pocos IDs de proceso

Cuando ocurren estas condiciones, kubelet evicta pods para asegurar recursos.

Eviction Policy Configuration

Las eviction policies se pueden establecer en la configuración de kubelet:

yaml
# kubelet configuration example
evictionHard:
  memory.available: "100Mi"
  nodefs.available: "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "15%"
evictionSoft:
  memory.available: "200Mi"
  nodefs.available: "15%"
evictionSoftGracePeriod:
  memory.available: "1m"
  nodefs.available: "2m"
evictionMinimumReclaim:
  memory.available: "50Mi"
  nodefs.available: "5%"
evictionPressureTransitionPeriod: "30s"

En el ejemplo anterior:

  • evictionMinimumReclaim: Recursos mínimos que deben recuperarse después de la eviction
  • evictionPressureTransitionPeriod: Tiempo de espera entre transiciones de estado de presión

TopologySpreadConstraints

TopologySpreadConstraints proporcionan control detallado sobre cómo se distribuyen los pods entre dominios de topología como availability zones, nodes o regions. Esta característica ofrece más flexibilidad que Pod anti-affinity para lograr alta disponibilidad y utilización eficiente de recursos.

Key Fields

FieldDescriptionRequired
maxSkewMaximum allowed difference in pod count between any two topology domainsYes
topologyKeyNode label key that defines topology domainsYes
whenUnsatisfiableAction when constraints cannot be satisfied: DoNotSchedule or ScheduleAnywayYes
labelSelectorSelects which pods to count for spread calculationYes
minDomainsMinimum number of topology domains required (1.27+)No
matchLabelKeysPod label keys to match for spread calculation (1.27+)No

whenUnsatisfiable Options

  • DoNotSchedule: El scheduler no programará el pod si la constraint no puede satisfacerse (hard constraint)
  • ScheduleAnyway: El scheduler aún programa el pod, dando mayor prioridad a nodes que minimizan el skew (soft constraint)

EKS Availability Zone Spread Example

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 6
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: web
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app: web
      containers:
      - name: web
        image: nginx:1.25
        resources:
          requests:
            cpu: 100m
            memory: 128Mi

Esta configuración garantiza:

  1. Los pods se distribuyen uniformemente entre availability zones (hard constraint)
  2. Los pods se distribuyen preferentemente entre nodes dentro de cada zone (soft constraint)

minDomains and matchLabelKeys (Kubernetes 1.27+)

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-min-domains
spec:
  replicas: 4
  selector:
    matchLabels:
      app: distributed-app
  template:
    metadata:
      labels:
        app: distributed-app
        version: v1
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: distributed-app
        minDomains: 3
        matchLabelKeys:
        - version
      containers:
      - name: app
        image: myapp:v1
  • minDomains: Garantiza que los pods se distribuyan entre al menos 3 zones. Si hay menos zones disponibles, el scheduling se bloquea.
  • matchLabelKeys: Usa automáticamente el valor del label version del pod en el selector, lo que permite spread por revision sin modificar el selector.

Advantages Over Pod Anti-Affinity

AspectTopologySpreadConstraintsPod Anti-Affinity
FlexibilityAllows controlled skew (maxSkew > 1)Binary: either same or different domain
Soft constraintsScheduleAnyway for best-effortpreferredDuringScheduling but less control
Multi-levelMultiple constraints with different topologyKeysRequires complex nested rules
PerformanceBetter scheduler performance at scaleCan slow scheduling with many pods
Use caseEven distribution with toleranceStrict separation

Pod Deletion Cost

Pod Deletion Cost es una característica que permite controlar qué pods se eliminan primero durante operaciones de scale-down. Al establecer la annotation controller.kubernetes.io/pod-deletion-cost, puedes influir en el orden en que se terminan los pods.

How It Works

Cuando un controller (como HPA o scale-down manual) necesita reducir replicas, considera:

  1. Los pods con menor deletion cost se eliminan primero
  2. El deletion cost predeterminado es 0
  3. Rango válido: -2147483648 a 2147483647

Basic Example

yaml
apiVersion: v1
kind: Pod
metadata:
  name: worker-pod
  annotations:
    controller.kubernetes.io/pod-deletion-cost: "100"
spec:
  containers:
  - name: worker
    image: worker:latest

HPA Scale-Down Priority Control

Usa deletion cost para proteger pods importantes durante el scale-down de HPA:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-service
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
      # Lower cost pods are deleted first during scale-down
      annotations:
        controller.kubernetes.io/pod-deletion-cost: "0"
    spec:
      containers:
      - name: web
        image: nginx:1.25

Cache Protection Pattern

Protege pods con caches calientes ajustando dinámicamente el deletion cost:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cache-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: cache
  template:
    metadata:
      labels:
        app: cache
    spec:
      containers:
      - name: cache
        image: redis:7
      - name: cost-updater
        image: bitnami/kubectl:latest
        command:
        - /bin/sh
        - -c
        - |
          # Update deletion cost based on cache warmth
          while true; do
            CACHE_SIZE=$(redis-cli DBSIZE | awk '{print $2}')
            # Higher cache size = higher cost = less likely to be deleted
            kubectl annotate pod $POD_NAME \
              controller.kubernetes.io/pod-deletion-cost="$CACHE_SIZE" \
              --overwrite
            sleep 60
          done
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name

Practical Use Cases

  1. Stateful workloads: Proteger pods con estado acumulado
  2. Leader election: Mantener los leader pods ejecutándose durante más tiempo
  3. Connection draining: Dar tiempo para conexiones de larga duración
  4. Cache warming: Preservar pods con caches calientes
  5. Batch processing: Mantener pods procesando jobs grandes

Descheduler

El Descheduler es un componente de Kubernetes que evicta pods de nodes para permitir que el scheduler los reprograme en nodes más apropiados. A diferencia del scheduler, que solo coloca pods nuevos, el descheduler ayuda a mantener la colocación óptima de pods a lo largo del tiempo.

Why Descheduling Is Needed

  1. Cluster changes: Nuevos nodes añadidos, labels de nodes cambiados
  2. Pod drift: La colocación inicial se vuelve subóptima con el tiempo
  3. Affinity violations: Reglas violadas después de cambios en el cluster
  4. Resource imbalance: Algunos nodes sobreutilizados, otros infrautilizados
  5. Failed pods: Pods atascados en bucles de reinicio

Key Strategies

StrategyDescriptionUse Case
RemoveDuplicatesRemoves duplicate pods from the same nodeEnsure HA after node failures
LowNodeUtilizationMoves pods from overutilized to underutilized nodesBalance cluster resources
RemovePodsHavingTooManyRestartsEvicts pods with excessive restartsClean up problematic pods
PodLifeTimeEvicts pods older than specified ageForce fresh scheduling
RemovePodsViolatingInterPodAntiAffinityEvicts pods violating anti-affinity rulesRestore affinity compliance
RemovePodsViolatingNodeAffinityEvicts pods violating node affinityRestore affinity compliance
RemovePodsViolatingTopologySpreadConstraintEvicts pods violating spread constraintsRestore even distribution

Helm Installation

bash
# Add the descheduler Helm repository
helm repo add descheduler https://kubernetes-sigs.github.io/descheduler/

# Install descheduler
helm install descheduler descheduler/descheduler \
  --namespace kube-system \
  --set schedule="*/5 * * * *" \
  --set deschedulerPolicy.strategies.RemoveDuplicates.enabled=true \
  --set deschedulerPolicy.strategies.LowNodeUtilization.enabled=true

DeschedulerPolicy Configuration

yaml
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: default
  pluginConfig:
  - name: RemoveDuplicates
    args:
      excludeOwnerKinds:
      - DaemonSet
  - name: LowNodeUtilization
    args:
      thresholds:
        cpu: 20
        memory: 20
        pods: 20
      targetThresholds:
        cpu: 50
        memory: 50
        pods: 50
      useDeviationThresholds: false
  - name: RemovePodsHavingTooManyRestarts
    args:
      podRestartThreshold: 10
      includingInitContainers: true
  - name: PodLifeTime
    args:
      maxPodLifeTimeSeconds: 86400  # 24 hours
      podStatusPhases:
      - Running
  - name: RemovePodsViolatingTopologySpreadConstraint
    args:
      constraints:
      - DoNotSchedule
  plugins:
    deschedule:
      enabled:
      - RemoveDuplicates
      - LowNodeUtilization
      - RemovePodsHavingTooManyRestarts
      - PodLifeTime
      - RemovePodsViolatingTopologySpreadConstraint

PDB Respect

El descheduler respeta Pod Disruption Budgets (PDBs). Si evictar un pod violaría un PDB, el descheduler no evictará ese pod:

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: web

Con este PDB aplicado, el descheduler garantizará que al menos 2 pods con el label app: web permanezcan disponibles durante las operaciones de descheduling.

Descheduler CronJob Example

yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: descheduler
  namespace: kube-system
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: descheduler
          containers:
          - name: descheduler
            image: registry.k8s.io/descheduler/descheduler:v0.28.0
            args:
            - --policy-config-file=/policy/policy.yaml
            - --v=3
            volumeMounts:
            - name: policy
              mountPath: /policy
          volumes:
          - name: policy
            configMap:
              name: descheduler-policy
          restartPolicy: OnFailure

Deep Dive: Para obtener información detallada sobre custom schedulers, consulta:

Scheduling Optimization in Amazon EKS

En Amazon EKS, puedes optimizar workloads usando características de scheduling de Kubernetes.

Node Groups and Instance Types

En EKS, puedes proporcionar recursos apropiados para workloads utilizando diversos node groups e instance types:

  1. Various Instance Types: Compute optimized, memory optimized, storage optimized, etc.
  2. Spot Instances: Spot instances para workloads rentables
  3. GPU Instances: GPU instances para workloads de AI/ML

Puedes usar node labels y taints para colocar workloads específicos en node groups específicos:

bash
# Set labels and taints when creating node group
eksctl create nodegroup \
  --cluster my-cluster \
  --name gpu-nodes \
  --node-labels="workload-type=gpu" \
  --node-type=p3.2xlarge \
  --taints="gpu=true:NoSchedule"

Availability Zone Distribution

En EKS, puedes distribuir workloads entre múltiples availability zones usando pod anti-affinity y topology spread constraints:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: web
      containers:
      - name: web
        image: nginx

En el ejemplo anterior, topologySpreadConstraints distribuye pods uniformemente entre múltiples availability zones.

Auto Scaling with Karpenter

En Amazon EKS, puedes usar Karpenter para aprovisionar automáticamente nodes apropiados para workloads:

yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64", "arm64"]
      nodeClassRef:
        name: default-class
  limits:
    cpu: 1000
    memory: 1000Gi
  disruption:
    consolidationPolicy: WhenEmpty
    consolidateAfter: 30s
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default-class
spec:
  subnetSelector:
    karpenter.sh/discovery: my-cluster
  securityGroupSelector:
    karpenter.sh/discovery: my-cluster

Karpenter optimiza los costos seleccionando el instance type óptimo para los requisitos de recursos del pod.

Resource Request and Limit Optimization

Optimizar los resource requests y limits de workloads en EKS es importante:

  1. Vertical Pod Autoscaler (VPA): Optimiza resource requests según el uso real de recursos del workload
  2. Goldilocks: Visualiza recomendaciones de VPA para apoyar la optimización de resource requests
  3. Resource Quotas: Limita el uso de recursos por namespace
yaml
# VPA example
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: frontend-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: frontend
  updatePolicy:
    updateMode: "Auto"

Scheduling Best Practices

Mejores prácticas para optimizar scheduling en Kubernetes y EKS:

  1. Set appropriate resource requests and limits:

    • Establece resource requests según el uso real de recursos del workload
    • Establece resource limits apropiados para workloads importantes
    • Usa VPA para optimizar automáticamente resource requests
  2. Workload distribution:

    • Usa pod anti-affinity para distribuir workloads importantes entre múltiples nodes
    • Usa topology spread constraints para distribuir workloads entre múltiples availability zones
    • Usa node affinity para colocar workloads específicos en nodes específicos
  3. Node resource optimization:

    • Usa diversos instance types para proporcionar recursos apropiados para workloads
    • Usa spot instances para optimizar costos
    • Usa Karpenter para el aprovisionamiento automático de nodes apropiados para workloads
  4. PDB configuration:

    • Establece PDB para workloads importantes
    • Selecciona valores de minAvailable o maxUnavailable apropiados para las características del workload
    • Prueba regularmente la operación del PDB
  5. Priority and preemption configuration:

    • Establece priority classes altas para workloads importantes
    • Usa priority classes system-cluster-critical o system-node-critical para componentes del sistema
    • Comprende y prueba el impacto de preemption
  6. Node taints and tolerations:

    • Establece nodes dedicados para workloads especializados
    • Aplica taints a nodes en mantenimiento
    • Establece tolerations apropiadas

Conclusion

Los mecanismos de scheduling, preemption y eviction de Kubernetes desempeñan funciones importantes para gestionar eficientemente los recursos del cluster y mantener la disponibilidad de workloads. Al comprender y utilizar estas características, puedes optimizar y operar workloads de forma confiable en clusters Amazon EKS.

La optimización de scheduling es un proceso continuo, y los ajustes deben realizarse continuamente según las características del workload y el estado del cluster. Es importante rastrear el uso de recursos del cluster usando herramientas de monitoreo y ajustar las scheduling policies según sea necesario.

Quiz

Para comprobar lo que aprendiste en este capítulo, intenta el Scheduling, Preemption, and Eviction Quiz.