Blog

Pod affinity y anti-affinity en kubernetes

En varias ocasiones algunos de nuestros clientes nos han planteado la misma inquietud: "¿Por qué si hay varias réplicas de un pod y hay varios nodos, la pérdida de un nodo ha llegado a provocar la caída de algún servicio? ¿Por qué se pierde servicio si hay alta disponibilidad y tengo varios nodos y varias réplicas?"

Un error muy común es pensar que el planificador de kubernetes va a distribuir sí o sí todas las réplicas de un pod en diferentes nodos. Esto suele ir seguido de una breve explicación por nuestra parte sobre kubernetes y la planificación de pods.

Es cierto que en la planificación se tiene en cuenta esta información pero no de manera estricta, es decir, el planificador va a intentar levantar réplicas de un mismo pod en distintos nodos, pero pueden darse otras condiciones dentro de la planificación, por las cuales se decida que ha de levantar los pods en otro nodo (aunque el nodo elegido ya tenga réplicas de dicho pod corriendo).

Si por la arquitectura de la plataforma, las planificaciones de pods que está realizando Kubernetes no son las más apropiadas, existen varias formas de configurarla.

Aunque existen varias formas y opciones de realizar configuración sobre la planificación de pods, en esta ocasión vamos a hablaros de la herramienta "pod affinity y anti-affinity".

Con la afinidad y antiafinidad de pods, vamos a indicarle al planificador condiciones (basadas en etiquetas/labels) para la distribución de los mismos.

Existen 2 tipos de afinidad y antiafinidad: suave y blanda (soft y hard). Para simplificar la explicación, vamos a tomar como referencia la antiafinidad de pods y comentaremos finalmente la afinidad.

Pod anti-affinity

Con una configuración de antiafinidad suave, establecemos reglas con "peso" para indicar al planificador las preferencias a la hora de distribuir los pods, pero no es un requisito indispensable. 

Esto quiere decir que si no se cumplieran las reglas antiafinidad de pods, podrían llegar a levantarse éstos en un nodo que no cumpla dicha condición (que ya haya una réplica de ese pod en ese nodo y levante una nueva réplica).

Con una configuración de antiafinidad dura, establecemos reglas como "requeridas" para la distribución de pods, las reglas han de cumplirse sí o sí. En caso contrario, no se levantará el pod.

Habiendo explicado la diferencia entre antiafinidad suave y dura, comentamos sus pros y contras.

Claramente, para solventar el caso con el que inicialmente comenzamos el artículo, una antiafinidad de pods dura podría ser una de las soluciones.

De esta forma aseguraremos que todas las réplicas de un pod son levantadas en distintos nodos y que la pérdida de un nodo no afectaría a servicio. En muchos casos esto puede ser recomendable y válido pero en otros casos esto podría jugar en nuestra contra.

Por ejemplo, en un caso donde un aplicativo funcione mejor con un escalado horizontal, es posible que se requiera tener más pods que números de nodos y en este caso una antiafinidad dura no nos permitiría levantar varias réplicas de un pod en el mismo nodo.

Para explicarlo mejor, proponemos el siguiente ejemplo donde tenemos un cluster de Kubernetes con 6 nodos de computación y vamos a levantar 1 Deployment con antiafinidad dura: primero, levantaremos 6 réplicas, veremos como ha repartido correctamente los pods en cada nodo y luego subiremos a 7 réplicas, siendo imposible asignar este 7º pod a ningún nodo pues ninguno de los nodos cumplirá la regla de antiafinidad siendo imposible levantar este nuevo pod. 

Para ello, vamos a utilizar el siguiente manifiesto:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: "str-testing-anti-affinity-hard"
  namespace: "testing"
spec:
  selector:
    matchLabels:
      anti-affinity: "Y"
  replicas: 6
  template:
    metadata:
      labels:
        anti-affinity: "Y"
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: anti-affinity
                operator: In
                values:
                - "Y"
            topologyKey: kubernetes.io/hostname
      containers:
      - name: echo-server-container
        image: "gcr.io/google-containers/echoserver:1.10"
        imagePullPolicy: Always
        ports:
        - containerPort: 8080

 

Con la anterior regla de antiafinidad, no se levantarán pods en nodos que ya tengan pods con la etiqueta anti-affinity con el valor “Y”.

Desplegamos 6

Desplegamos 7 (cambiando el parámetro “replicas” a 7)

Como podéis ver, cuando hemos intentado levantar la 7ª réplica no ha sido posible porque no se cumplía la regla de antiafinidad en ninguno de los 6 nodos al ya tener réplicas de ese pod levantadas.

Por otro lado, tenemos la antiafinidad blandaComo comentamos inicialmente, establece preferencias por pesos para la distribución de pods.

Kubernetes tratará las reglas de antiafinidad y planificará la distribución en base a ello, pero si algún nodo no cumple los requisitos de esto y no hay más nodos disponibles, esta regla de antiafinidad no será un requisito indispensable y tratará de levantar el pod en un nodo aunque ya tenga réplicas del mismo pod levantadas.

Para ello utilizaremos el siguiente manifiesto:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: "str-testing-anti-affinity-soft"
  namespace: "testing"
spec:
  selector:
    matchLabels:
      anti-affinity: X
  replicas: 6
  template:
    metadata:
      labels:
        anti-affinity: X
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: anti-affinity
                  operator: In
                  values:
                  - X
              topologyKey: kubernetes.io/hostname
      containers:
      - name: echo-server-container
        image: "gcr.io/google-containers/echoserver:1.10"
        imagePullPolicy: Always
        ports:
        - containerPort: 8080

 

Con la anterior regla de antiafinidad, no se levantarán pods en nodos que ya tengan pods con la etiqueta “anti-affinity” con el valor “X”.

Como podemos observar, todos los pods se han desplegado en nodos diferentes.  No obstante, al subir a 7 réplicas en un nodo se levantarán 2.

Pod affinity

Por último, comentar que de igual forma que hemos utilizado las reglas de antiafinidad, podemos utilizar reglas de afinidad, es un simple cambio en los manifiestos anteriores, reemplazando:


 spec:
      affinity:
        podAntiAffinity:

por:


    spec:
      affinity:
        podAffinity:

 

Newsletter de STR Sistemas

Suscríbete a nuestra newsletter para recibir contenido interesante del mundo DevOps y artículos escritos por nuestros técnicos

¡Usamos cookies propias y de terceros para mejorar tu experiencia en esta web! Si sigues navegando, consientes y aceptas estas cookies en tu ordenador, móvil o tablet.

Más información sobre las cookies y cómo cambiar su configuración en tu navegador aquí.

x