Estos contenidos se han traducido de forma automática para su comodidad, pero Huawei Cloud no garantiza la exactitud de estos. Para consultar los contenidos originales, acceda a la versión en inglés.
Centro de ayuda/ Cloud Container Engine/ Guía del usuario/ Workloads/ Configuring a Container/ Política de programación (afinidad/antiafinidad)
Actualización más reciente 2024-09-10 GMT+08:00

Política de programación (afinidad/antiafinidad)

Un nodeSelector proporciona una forma muy sencilla de restringir pods a nodos con etiquetas particulares, como se menciona en Creación de un DaemonSet. La función de afinidad y antiafinidad amplía enormemente los tipos de restricciones que puede expresar.

Kubernetes admite afinidad y antiafinidad a nivel de nodo y de pod. Puede configurar reglas personalizadas para lograr una programación de afinidad y antiafinidad.For example, you can deploy frontend pods and backend pods together, deploy the same type of applications on a specific node, or deploy different applications on different nodes.

Node Affinity (nodeAffinity)

Labels are the basis of affinity rules. Let's look at the labels on nodes in a cluster.

$ kubectl describe node 192.168.0.212
Name:               192.168.0.212
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    failure-domain.beta.kubernetes.io/is-baremetal=false
                    failure-domain.beta.kubernetes.io/region=******
                    failure-domain.beta.kubernetes.io/zone=******
                    kubernetes.io/arch=amd64
                    kubernetes.io/availablezone=******
                    kubernetes.io/eniquota=12
                    kubernetes.io/hostname=192.168.0.212
                    kubernetes.io/os=linux
                    node.kubernetes.io/subnetid=fd43acad-33e7-48b2-a85a-24833f362e0e
                    os.architecture=amd64
                    os.name=EulerOS_2.0_SP5
                    os.version=3.10.0-862.14.1.5.h328.eulerosv2r7.x86_64

Estas etiquetas son agregadas automáticamente por CCE durante la creación del nodo. A continuación se describen algunas que se utilizan con frecuencia durante la programación.

  • failure-domain.beta.kubernetes.io/region: región donde se encuentra el nodo.
  • failure-domain.beta.kubernetes.io/zone: zona de disponibilidad a la que pertenece el nodo.
  • kubernetes.io/hostname: nombre de host del nodo.

Cuando despliega pods, puede usar un nodeSelector, como se describe en el documento DaemonSet para restringir pods a nodos con las etiquetas específicas. En el ejemplo siguiente se muestra cómo utilizar un nodeSelector para desplegar pods solo en los nodos con la etiqueta gpu=true.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector:                 # Node selection. A pod is deployed on a node only when the node has the gpu=true label.
    gpu: true
...
Las reglas de afinidad de nodo pueden lograr los mismos resultados, como se muestra en el siguiente ejemplo.
apiVersion: apps/v1
kind: Deployment
metadata:
  name:  gpu
  labels:
    app:  gpu
spec:
  selector:
    matchLabels:
      app: gpu
  replicas: 3
  template:
    metadata:
      labels:
        app:  gpu
    spec:
      containers:
      - image:  nginx:alpine
        name:  gpu
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
          limits:
            cpu: 100m
            memory: 200Mi
      imagePullSecrets:
      - name: default-secret
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: gpu
                operator: In
                values:
                - "true"

Aunque la regla de afinidad de nodo requiere más líneas, es más expresiva, lo que se describirá más adelante.

requiredDuringSchedulingIgnoredDuringExecution parece ser complejo, pero puede entenderse fácilmente como una combinación de dos partes.

  • requiredDuringScheduling indica que los pods se pueden programar en el nodo solo cuando se cumplen todas las reglas definidas (requerido).
  • IgnoredDuringExecution indica que los pods que ya se están ejecutando en el nodo no necesitan cumplir las reglas definidas. Es decir, se ignora una etiqueta en el nodo, y los pods que requieren que el nodo contenga esa etiqueta no se reprogramarán.

Además, el valor de operator es In, indicando que el valor de la etiqueta debe estar en la lista de valores. Otros valores de operador disponibles son los siguientes:

  • NotIn: El valor de etiqueta no está en una lista.
  • Exists: Existe una etiqueta específica.
  • DoesNotExist: No existe una etiqueta específica.
  • Gt: El valor de etiqueta es mayor que un valor especificado (comparación de cadenas).
  • Lt: El valor de etiqueta es menor que un valor especificado (comparación de cadenas).

Tenga en cuenta que no hay tal cosa como nodeAntiAffinity porque los operadores NotIn y DoesNotExist proporcionan la misma función.

A continuación se describe cómo comprobar si la regla tiene efecto. Suponga que un clúster tiene tres nodos.

$ kubectl get node
NAME            STATUS   ROLES    AGE   VERSION                            
192.168.0.212   Ready    <none>   13m   v1.15.6-r1-20.3.0.2.B001-15.30.2
192.168.0.94    Ready    <none>   13m   v1.15.6-r1-20.3.0.2.B001-15.30.2   
192.168.0.97    Ready    <none>   13m   v1.15.6-r1-20.3.0.2.B001-15.30.2   

Agregue la etiqueta gpu=true al nodo 192.168.0.212.

$ kubectl label node 192.168.0.212 gpu=true
node/192.168.0.212 labeled

$ kubectl get node -L gpu
NAME            STATUS   ROLES    AGE   VERSION                            GPU
192.168.0.212   Ready    <none>   13m   v1.15.6-r1-20.3.0.2.B001-15.30.2   true
192.168.0.94    Ready    <none>   13m   v1.15.6-r1-20.3.0.2.B001-15.30.2   
192.168.0.97    Ready    <none>   13m   v1.15.6-r1-20.3.0.2.B001-15.30.2   

Cree la Deployment. Puede encontrar que todos los pods se despliegan en el nodo 192.168.0.212.

$ kubectl create -f affinity.yaml 
deployment.apps/gpu created

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE         
gpu-6df65c44cf-42xw4     1/1     Running   0          15s   172.16.0.37   192.168.0.212
gpu-6df65c44cf-jzjvs     1/1     Running   0          15s   172.16.0.36   192.168.0.212
gpu-6df65c44cf-zv5cl     1/1     Running   0          15s   172.16.0.38   192.168.0.212

Regla de preferencia de nodo

La regla requiredDuringSchedulingIgnoredDuringExecution anterior es una regla de selección dura. Hay otro tipo de regla de selección, es decir, preferredDuringSchedulingIgnoredDuringExecution. Se utiliza para especificar qué nodos se prefieren durante la planificación.

Para lograr este efecto, agregue un nodo conectado con discos de SAS al clúster, agregue la etiqueta DISK=SAS al nodo y agregue la etiqueta DISK=SSD a los otros tres nodos.

$ kubectl get node -L DISK,gpu
NAME            STATUS   ROLES    AGE     VERSION                            DISK     GPU
192.168.0.100   Ready    <none>   7h23m   v1.15.6-r1-20.3.0.2.B001-15.30.2   SAS   
192.168.0.212   Ready    <none>   8h      v1.15.6-r1-20.3.0.2.B001-15.30.2   SSD      true
192.168.0.94    Ready    <none>   8h      v1.15.6-r1-20.3.0.2.B001-15.30.2   SSD   
192.168.0.97    Ready    <none>   8h      v1.15.6-r1-20.3.0.2.B001-15.30.2   SSD  

Defina una Deployment. Utilice la regla preferredDuringSchedulingIgnoredDuringExecution para establecer la ponderación de los nodos con el disco de SSD instalado como 80 y los nodos con la etiqueta gpu=true como 20. De esta manera, los pods se despliegan preferentemente en los nodos con el disco SSD instalado.

apiVersion: apps/v1
kind: Deployment
metadata:
  name:  gpu
  labels:
    app:  gpu
spec:
  selector:
    matchLabels:
      app: gpu
  replicas: 10
  template:
    metadata:
      labels:
        app:  gpu
    spec:
      containers:
      - image:  nginx:alpine
        name:  gpu
        resources:
          requests:
            cpu:  100m
            memory:  200Mi
          limits:
            cpu:  100m
            memory:  200Mi
      imagePullSecrets:
      - name: default-secret
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80 
            preference: 
              matchExpressions: 
              - key: DISK
                operator: In 
                values: 
                - SSD
          - weight: 20 
            preference: 
              matchExpressions: 
              - key: gpu
                operator: In 
                values: 
                - "true"

Después del despliegue, hay cinco pods desplegados en el nodo 192.168.0.212 (etiqueta: DISK=SSD y GPU=true), tres pods desplegados en el nodo 192.168.0.97 (etiqueta: DISK=SSD), y dos pods desplegados en el nodo 192.168.0.100 (etiqueta: DISK=SAS).

En la salida anterior, puede encontrar que ningún pod de la Deployment está programado al nodo 192.168.0.94 (etiqueta:DISK=SSD). Esto se debe a que el nodo ya tiene muchos pods en él y su uso de recursos es alto. Esto también indica que la regla preferredDuringSchedulingIgnoredDuringExecution define una preferencia en lugar de un requisito difícil.

$ kubectl create -f affinity2.yaml 
deployment.apps/gpu created

$ kubectl get po -o wide
NAME                   READY   STATUS    RESTARTS   AGE     IP            NODE         
gpu-585455d466-5bmcz   1/1     Running   0          2m29s   172.16.0.44   192.168.0.212
gpu-585455d466-cg2l6   1/1     Running   0          2m29s   172.16.0.63   192.168.0.97 
gpu-585455d466-f2bt2   1/1     Running   0          2m29s   172.16.0.79   192.168.0.100
gpu-585455d466-hdb5n   1/1     Running   0          2m29s   172.16.0.42   192.168.0.212
gpu-585455d466-hkgvz   1/1     Running   0          2m29s   172.16.0.43   192.168.0.212
gpu-585455d466-mngvn   1/1     Running   0          2m29s   172.16.0.48   192.168.0.97 
gpu-585455d466-s26qs   1/1     Running   0          2m29s   172.16.0.62   192.168.0.97 
gpu-585455d466-sxtzm   1/1     Running   0          2m29s   172.16.0.45   192.168.0.212
gpu-585455d466-t56cm   1/1     Running   0          2m29s   172.16.0.64   192.168.0.100
gpu-585455d466-t5w5x   1/1     Running   0          2m29s   172.16.0.41   192.168.0.212

En el ejemplo anterior, la prioridad de planificación de nodo es como sigue. Los nodos con etiquetas SSD y gpu=true tienen la prioridad más alta. Los nodos con la etiqueta SSD pero sin etiqueta gpu=true tienen la segunda prioridad (peso: 80). Los nodos con la etiqueta gpu=true pero sin etiqueta SSD tienen la tercera prioridad. Los nodos sin ninguna de estas dos etiquetas tienen la prioridad más baja.

Figura 1 Planificación de prioridades

Afinidad de la carga de trabajo (podAffinity)

Las reglas de afinidad de nodos afectan solo a la afinidad entre pods y nodos. Kubernetes también admite la configuración de reglas de afinidad dentro de pod. Por ejemplo, el frontend y el backend de una aplicación se pueden desplegar juntos en un nodo para reducir la latencia de acceso. También hay dos tipos de reglas de afinidad dentro de pod: requiredDuringSchedulingIgnoredDuringExecution y preferredDuringSchedulingIgnoredDuringExecution.

Suponga que el backend de una aplicación ha sido creado y tiene la etiqueta app=backend.

$ kubectl get po -o wide
NAME                       READY   STATUS    RESTARTS   AGE     IP            NODE         
backend-658f6cb858-dlrz8   1/1     Running   0          2m36s   172.16.0.67   192.168.0.100

Puede configurar la siguiente regla de afinidad de pod para desplegar los pods frontend de la aplicación en el mismo nodo que los pods backend.

apiVersion: apps/v1
kind: Deployment
metadata:
  name:   frontend
  labels:
    app:  frontend
spec:
  selector:
    matchLabels:
      app: frontend
  replicas: 3
  template:
    metadata:
      labels:
        app:  frontend
    spec:
      containers:
      - image:  nginx:alpine
        name:  frontend
        resources:
          requests:
            cpu:  100m
            memory:  200Mi
          limits:
            cpu:  100m
            memory:  200Mi
      imagePullSecrets:
      - name: default-secret
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            labelSelector:
              matchExpressions: 
              - key: app
                operator: In 
                values: 
                - backend

Despliegue el frontend y puede encontrar que el frontend se despliega en el mismo nodo que el backend.

$ kubectl create -f affinity3.yaml 
deployment.apps/frontend created

$ kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP            NODE         
backend-658f6cb858-dlrz8    1/1     Running   0          5m38s   172.16.0.67   192.168.0.100
frontend-67ff9b7b97-dsqzn   1/1     Running   0          6s      172.16.0.70   192.168.0.100
frontend-67ff9b7b97-hxm5t   1/1     Running   0          6s      172.16.0.71   192.168.0.100
frontend-67ff9b7b97-z8pdb   1/1     Running   0          6s      172.16.0.72   192.168.0.100

El campo topologyKey se utiliza para dividir dominios de topología para especificar el rango de selección. Si las claves de etiqueta y los valores de los nodos son los mismos, se considera que los nodos están en el mismo dominio de topología. A continuación, se seleccionan los contenidos definidos en las siguientes reglas. El efecto de topologyKey no se demuestra completamente en el ejemplo anterior porque todos los nodos tienen la etiqueta kubernetes.io/hostname. Es decir, todos los nodos están dentro del rango.

Para ver cómo funciona topologyKey, suponga que el backend de la aplicación tiene dos pods, que se ejecutan en los nodos diferentes.

$ kubectl get po -o wide
NAME                       READY   STATUS    RESTARTS   AGE     IP            NODE         
backend-658f6cb858-5bpd6   1/1     Running   0          23m     172.16.0.40   192.168.0.97
backend-658f6cb858-dlrz8   1/1     Running   0          2m36s   172.16.0.67   192.168.0.100

Agregue la etiqueta prefer=true a los nodos 192.168.0.97 y 192.168.0.94.

$ kubectl label node 192.168.0.97 prefer=true
node/192.168.0.97 labeled
$ kubectl label node 192.168.0.94 prefer=true
node/192.168.0.94 labeled

$ kubectl get node -L prefer
NAME            STATUS   ROLES    AGE   VERSION                            PREFER
192.168.0.100   Ready    <none>   44m   v1.15.6-r1-20.3.0.2.B001-15.30.2   
192.168.0.212   Ready    <none>   91m   v1.15.6-r1-20.3.0.2.B001-15.30.2   
192.168.0.94    Ready    <none>   91m   v1.15.6-r1-20.3.0.2.B001-15.30.2   true
192.168.0.97    Ready    <none>   91m   v1.15.6-r1-20.3.0.2.B001-15.30.2   true

Si la topologyKey de podAffinity se establece en prefer, los dominios de topología de nodo se dividen como se muestra en Figura 2.

      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: prefer
            labelSelector:
              matchExpressions: 
              - key: app
                operator: In 
                values: 
                - backend
Figura 2 Dominios de topología

Durante la planificación, los dominios de topología de nodo se dividen en función de la etiqueta prefer. En este ejemplo, las 192.168.0.97 y 192.168.0.94 se dividen en el mismo dominio de topología. Si un pod con la etiqueta app=backend se ejecuta en el dominio de topología, aunque no todos los nodos del dominio de topología ejecuten el pod con la etiqueta app=backend (en este ejemplo, solo el nodo 192.168.0.97 tiene tal pod) frontend también se despliega en este dominio de topología (192.168.0.97 o 192.168.0.94).

$ kubectl create -f affinity3.yaml 
deployment.apps/frontend created

$ kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP            NODE         
backend-658f6cb858-5bpd6    1/1     Running   0          26m     172.16.0.40   192.168.0.97
backend-658f6cb858-dlrz8    1/1     Running   0          5m38s   172.16.0.67   192.168.0.100
frontend-67ff9b7b97-dsqzn   1/1     Running   0          6s      172.16.0.70   192.168.0.97
frontend-67ff9b7b97-hxm5t   1/1     Running   0          6s      172.16.0.71   192.168.0.97
frontend-67ff9b7b97-z8pdb   1/1     Running   0          6s      172.16.0.72   192.168.0.97

Antiafinidad de carga de trabajo (podAntiAffinity)

A diferencia de los escenarios en los que se prefiere que los pods se planifiquen en el mismo nodo, a veces, podría ser exactamente lo contrario. Por ejemplo, si ciertos pods se despliegan juntos, afectarán al rendimiento.

El siguiente es un ejemplo de definición de una regla antiafinidad. Esta regla divide los dominios de topología de nodo por la etiqueta kubernetes.io/hostname. Si ya existe un pod con la etiqueta app=frontend en un nodo del dominio de topología, los pods con la misma etiqueta no se pueden programar en otros nodos del dominio de topología.

apiVersion: apps/v1
kind: Deployment
metadata:
  name:   frontend
  labels:
    app:  frontend
spec:
  selector:
    matchLabels:
      app: frontend
  replicas: 5
  template:
    metadata:
      labels:
        app:  frontend
    spec:
      containers:
      - image:  nginx:alpine
        name:  frontend
        resources:
          requests:
            cpu:  100m
            memory:  200Mi
          limits:
            cpu:  100m
            memory:  200Mi
      imagePullSecrets:
      - name: default-secret
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname   # Topology domain of the node
            labelSelector:    # Pod label matching rule
              matchExpressions: 
              - key: app
                operator: In 
                values: 
                - frontend

Cree una regla de antiafinidad y vea el resultado despliegue. En el ejemplo, los dominios de topología de nodo se dividen por la etiqueta kubernetes.io/hostname. Los valores de etiqueta de los nodos con la etiqueta kubernetes.io/hostname son diferentes, por lo que solo hay un nodo en un dominio de topología. Si ya existe un pod con la etiqueta frontend en un dominio de topología (un nodo en este ejemplo), el dominio de topología no programará pods con la misma etiqueta. En este ejemplo, solo hay cuatro nodos. Por lo tanto, hay un pod que está en el estado Pending y no se puede programar.

$ kubectl create -f affinity4.yaml 
deployment.apps/frontend created

$ kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP            NODE         
frontend-6f686d8d87-8dlsc   1/1     Running   0          18s   172.16.0.76   192.168.0.100
frontend-6f686d8d87-d6l8p   0/1     Pending   0          18s   <none>        <none>
frontend-6f686d8d87-hgcq2   1/1     Running   0          18s   172.16.0.54   192.168.0.97 
frontend-6f686d8d87-q7cfq   1/1     Running   0          18s   172.16.0.47   192.168.0.212
frontend-6f686d8d87-xl8hx   1/1     Running   0          18s   172.16.0.23   192.168.0.94 

Configuración de políticas de programación

  1. Inicie sesión en la consola de CCE.
  2. Cuando cree una carga de trabajo, haga clic en Scheduling en el área Advanced Settings.

    Tabla 1 Configuración de afinidad de nodo

    Parámetro

    Descripción

    Required

    Esta es una regla dura que se debe cumplir para la programación. Corresponde a requiredDuringSchedulingIgnoredDuringExecution en Kubernetes. Se pueden establecer varias reglas requeridas, y la programación se realizará si solo se cumple una de ellas.

    Preferred

    Esta es una regla flexible que especifica las preferencias que el planificador intentará aplicar, pero no garantiza. Corresponde a preferredDuringSchedulingIgnoredDuringExecution en Kubernetes. La programación se realiza cuando se cumple una regla o cuando no se cumple ninguna de las reglas.

  3. En Node Affinity, Workload Affinity y Workload Anti-Affinity, haga clic en para agregar políticas de programación. En el cuadro de diálogo que se muestra, agregue una política directamente o especificando un nodo o una AZ.

    La especificación de un nodo o una AZ se implementa esencialmente con etiquetas. La etiqueta kubernetes.io/hostname se utiliza cuando se especifica un nodo y la etiqueta failure-domain.beta.kubernetes.io/zone se utiliza cuando se especifica una AZ.
    Tabla 2 Configuración de políticas de programación

    Parámetro

    Descripción

    Label

    Etiqueta del nodo. Puede utilizar la etiqueta predeterminada o personalizar una etiqueta.

    Operator

    Se apoyan las siguientes relaciones: In, NotIn, Exists, DoesNotExist, Gt y Lt

    • In: Existe una etiqueta en la lista de etiquetas.
    • NotIn: Una etiqueta no existe en la lista de etiquetas.
    • Exists: Existe una etiqueta específica.
    • DoesNotExist: No existe una etiqueta específica.
    • Gt: El valor de etiqueta es mayor que un valor especificado (comparación de cadenas).
    • Lt: El valor de etiqueta es menor que un valor especificado (comparación de cadenas).

    Label Value

    Valor de etiqueta.

    Namespace

    Este parámetro solo está disponible en una política de programación de afinidad o antiafinidad de carga de trabajo.

    Espacio de nombres para el que entra en vigor la política de programación.

    Topology Key

    Este parámetro solo se puede utilizar en una política de programación de afinidad o antiafinidad de carga de trabajo.

    Seleccione el ámbito especificado por topologyKey y, a continuación, seleccione el contenido definido por la política.

    Weight

    Este parámetro solo se puede establecer en una política de programación de Preferred.