Programación de afinidad y antiafinidad

En DaemonSet, hablamos sobre el uso de nodeSelector para seleccionar los nodos que Podrá implementar. De hecho, Kubernetes también admite un mecanismo de programación más refinado y flexible, es decir, programación de afinidad y antiafinidad.

Kubernetes admite dos niveles de afinidad y antiafinidad de nodos y pods. Al configurar reglas de afinidad y antiafinidad, puede especificar restricciones o preferencias estrictas, como implementar un pod de front-end y un pod de back-end juntos, implementar ciertos tipos de aplicaciones en nodos específicos, implementar diferentes aplicaciones en diferentes nodos, etc. .

Afinidad de nodo (afinidad de nodo)

Debes haber adivinado que la base de las reglas de afinidad deben ser etiquetas. Echemos un vistazo a las etiquetas de los nodos del clúster CCE.

$ 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=cn-east-3
                    failure-domain.beta.kubernetes.io/zone=cn-east-3a
                    kubernetes.io/arch=amd64
                    kubernetes.io/availablezone=cn-east-3a
                    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 el CCE cuando se crea el nodo. A continuación se presentan algunas etiquetas que se utilizarán más en la programación.

  • failure-domain.beta.kubernetes.io/region: indica la región donde se encuentra el nodo. Si el valor de la etiqueta del nodo anterior es cn-east-3, significa que el nodo está en una región de Shanghai.
  • failure-domain.beta.kubernetes.io/zone: indica la zona de disponibilidad (zona de disponibilidad) donde se encuentra el nodo.
  • kubernetes.io/hostname: el nombre de host del nodo.
    Además, en Label: The Weapon of Organizing Pods, también se introducen etiquetas personalizadas. Generalmente, para un clúster de Kubernetes grande, muchas etiquetas se definirán de acuerdo con las necesidades comerciales.

En DaemonSet, se introduce nodeSelector. A través de nodeSelector, Pod se puede implementar solo en nodos con etiquetas específicas. Como se muestra a continuación, el pod solo se implementará en los nodos con la etiqueta gpu = true.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector:                 # 节点选择,当节点拥有gpu=true时才在节点上创建Pod
    gpu: true
...

Se puede hacer lo mismo mediante la configuración de la regla de afinidad de nodo, como se muestra a continuación.

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"

Parece que esto es mucho más complicado, pero de esta manera se puede conseguir una mayor capacidad expresiva, que se introducirá más adelante.

Aquí, afinidad significa afinidad, nodeAffinity significa afinidad de nodo, requiredDuringSchedulingIgnoredDuringExecution es muy largo, pero esto se puede dividir en dos párrafos:

  • La primera mitad de requiredDuringScheduling indica que las reglas definidas a continuación deben cumplirse obligatoriamente (require).
  • La segunda mitad de IgnoredDuringExecution dijo que no afectará a los pods que ya se están ejecutando en el nodo. Las reglas actuales proporcionadas por Kubernetes terminan con IgnoredDuringExecution, porque las reglas de afinidad de nodo actuales solo afectarán a los pods que se están programando. Por último, kubernetes también admitirá RequiredDuringExecution, es decir, elimine una determinada etiqueta en el nodo, y se eliminarán los pods que necesitan que el nodo contenga la etiqueta.
  • Además, el valor del operador operador es In, lo que indica que el valor de la etiqueta debe estar en la lista de valores, y los valores de otros operadores son los siguientes.
  • NotIn: el valor de la etiqueta no está en una lista
  • Existe: existe una etiqueta
  • DoesNotExist: una etiqueta no existe
  • Gt: el valor de la etiqueta es mayor que cierto valor (comparación de cadenas)
  • Lt: El valor de la etiqueta es menor que un cierto valor (comparación de cadenas)
    Cabe señalar que no hay nodeAntiAffinity (antiafinidad de nodo), porque NotIn y DoesNotExist pueden proporcionar la misma función.

Verifiquemos si esta regla tiene efecto. Primero, etiquete el nodo 192.168.0.212 con gpu = true.

$ 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 esta implementación, puede encontrar que todos los pods están implementados en el nodo 192.168.0.212.

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

$ kubectl get pod -owide
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

Reglas de selección de prioridad de nodo

La requiredDuringSchedulingIgnoredDuringExecution mencionada anteriormente es una regla de selección obligatoria. También hay una regla de selección de prioridad para la afinidad de nodos, es decir, favoriteDuringSchedulingIgnoredDuringExecution, que indica qué nodos se seleccionarán preferentemente de acuerdo con las reglas.

Para demostrar este efecto, primero agregue un nodo al clúster anterior, y este nodo no está en la misma zona de disponibilidad que los otros tres nodos. Después de la creación, consulte la etiqueta de la zona de disponibilidad del nodo, como se muestra a continuación, el nodo recién agregado está en cn-este -3c esta zona disponible.

$ kubectl get node -L failure-domain.beta.kubernetes.io/zone,gpu
NAME            STATUS   ROLES    AGE     VERSION                            ZONE         GPU
192.168.0.100   Ready    <none>   7h23m   v1.15.6-r1-20.3.0.2.B001-15.30.2   cn-east-3c   
192.168.0.212   Ready    <none>   8h      v1.15.6-r1-20.3.0.2.B001-15.30.2   cn-east-3a   true
192.168.0.94    Ready    <none>   8h      v1.15.6-r1-20.3.0.2.B001-15.30.2   cn-east-3a   
192.168.0.97    Ready    <none>   8h      v1.15.6-r1-20.3.0.2.B001-15.30.2   cn-east-3a  

A continuación, se define una implementación que requiere que el pod se implemente en los nodos de la zona de disponibilidad cn-east-3a primero. Se puede definir de la siguiente manera, utilizando la regla favoriteDuringSchedulingIgnoredDuringExecution, y establezca el peso de cn-east-3a en 80 y gpu = true weight Es 20, por lo que Pod se implementará primero en el nodo cn-east-3a.

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: failure-domain.beta.kubernetes.io/zone
                operator: In 
                values: 
                - cn-east-3a
          - weight: 20 
            preference: 
              matchExpressions: 
              - key: gpu
                operator: In 
                values: 
                - "true"

Al observar la situación de implementación real, puede ver que hay 5 pods implementados en el nodo 192.168.0.212, mientras que solo hay 2 en 192.168.0.100.

$ 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 la clasificación de nodos es la siguiente. Un nodo con dos etiquetas ocupa el primer lugar. Solo el nodo con la etiqueta cn-east-3a ocupa el segundo lugar (peso 80) y solo el nodo con gpu = true ocupa el primer lugar. En tercer lugar, los nodos que no tienen la clasificación más baja.

Figura 1 Orden de clasificación de prioridad

Programación de afinidad y antiafinidad

Aquí puede ver que el pod no está programado en el nodo 192.168.0.94. Esto se debe a que hay muchos otros pods implementados en este nodo, que usa más recursos, por lo que no está programado en este nodo. Esto también muestra que favoriteDuringSchedulingIgnoredDuringExecution es la regla de prioridad. , No reglas obligatorias.

Pod Affinity (Pod Affinity)

Las reglas de afinidad de nodo solo pueden afectar la afinidad entre el pod y el nodo. Kubernetes también admite la afinidad entre el pod y el pod, como implementar el front-end y el back-end de la aplicación juntos para reducir la latencia de acceso. La afinidad de pod también tiene dos reglas: requiredDuringSchedulingIgnoredDuringExecution y favoriteDuringSchedulingIgnoredDuringExecution.

Eche un vistazo al siguiente ejemplo, asumiendo que se ha creado un backend de aplicación 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

Al implementar el pod de frontend junto con el backend, puede realizar la siguiente configuración de reglas de afinidad de pod.

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:
              matchLabels:
                app: backend

Cree la interfaz y luego verifíquela, puede ver que la interfaz se crea 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

Hay un campo topologyKey, que significa primero delimitar el rango especificado por topologyKey, y luego seleccionar el contenido definido por las siguientes reglas. Hay kubernetes.io/hostname en cada nodo aquí, por lo que no se ve el rol de topologyKey.

Si el backend tiene dos pods, están en diferentes nodos.

$ 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

Etiqueta 192.168.0.97 y 192.168.0.94 con perfer = true.

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

$ kubectl get node -L perfer
NAME            STATUS   ROLES    AGE   VERSION                            PERFER
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

Defina la topologyKey de podAffinity como prefiera.

        affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: perfer
            labelSelector:
              matchLabels:
                app: backend

Al programar, primero encierre en un círculo los nodos con la etiqueta de preferencia, aquí están 192.168.0.97 y 192.168.0.94, y luego haga coincidir el Pod con la etiqueta app = backend, para que todas las interfaces se implementen en 192.168.0.97.

$ 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

Pod AntiAffinity (Pod Anti-Affinity)

Hablé sobre la afinidad de los pods. Los pods se implementan juntos a través de la afinidad. A veces, los requisitos son todo lo contrario. Los pods deben implementarse por separado. Por ejemplo, la implementación de pods juntos afectará el rendimiento.

El siguiente ejemplo define una regla de antiafinidad. Esta regla indica que el pod no se puede programar en el nodo con la etiqueta app = frontend Pod, es decir, el frontend está programado en diferentes nodos (cada nodo tiene solo un pod).

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
            labelSelector:
              matchLabels:
                app: frontend

Cree y visualice, puede ver que solo hay un pod de frontend en cada nodo y uno está pendiente. Porque cuando se implementa el quinto, los cuatro nodos tienen pods con app = frontend, por lo que el quinto siempre está pendiente .

$ 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 

Supongo que te gusta

Origin blog.51cto.com/14051317/2553703
Recomendado
Clasificación