Coloque los pods de Kubernetes en Amazon EKS mediante la afinidad, las taints y las tolerancias de nodos - Recomendaciones de AWS

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Coloque los pods de Kubernetes en Amazon EKS mediante la afinidad, las taints y las tolerancias de nodos

Creado por Hitesh Parikh (AWS) y Raghu Bhamidimarri (AWS)

Entorno: PoC o piloto

Tecnologías: contenedores y microservicios

Carga de trabajo: código abierto

Servicios de AWS: Amazon EKS

Resumen

Este patrón muestra el uso de la afinidad de nodos de Kubernetes, las taints de nodos y las tolerancias de los pods para programar intencionalmente los pods de aplicaciones en nodos de trabajo específicos de un clúster de Amazon Elastic Kubernetes Service (Amazon EKS) en la nube de Amazon Web Services (AWS).

Una taint es una propiedad de un nodo que permite a los nodos rechazar un conjunto de pods. Una tolerancia es una propiedad de los pods que permite al programador de Kubernetes programar los pods en los nodos que tengan las mismas taints.

Sin embargo, las tolerancias por sí solas no pueden impedir que un programador coloque un pod en un nodo de trabajo que no contenga taints. Por ejemplo, un pod de procesamiento intensivo con una tolerancia puede programarse involuntariamente en un nodo no contaminado de uso general. En ese escenario, la propiedad de afinidad de nodos de un pod indica al planificador que coloque el pod en un nodo que cumpla con los criterios de selección de nodos especificados en la afinidad de nodos.

La combinación de taint, tolerancia y la afinidad de nodos indica al programador que programe los pods de forma coherente en los nodos, con las taints coincidentes y las etiquetas de nodo que coincidan con los criterios de selección de nodos de afinidad de nodos especificados en el pod.

Este patrón proporciona un ejemplo de un archivo de manifiesto de implementación de Kubernetes y los pasos para crear un clúster de EKS, implementar una aplicación y validar la ubicación del pod.

Requisitos previos y limitaciones

Requisitos previos 

Limitaciones

  • Este patrón no proporciona el código Java y supone que ya está familiarizado con Java. Para crear un microservicio Java básico, consulte Implementación de un microservicio Java de muestra en Amazon EKS.

  • Los pasos de este artículo crean recursos de AWS que pueden acumular costos. Asegúrese de limpiar los recursos de AWS una vez que haya completado los pasos para implementar y validar el patrón.

Arquitectura

Pila de tecnología de destino

  • Amazon EKS

  • Java

  • Docker

  • Amazon Elastic Container Registry (Amazon ECR)

Arquitectura de destino

El diagrama de arquitectura de la solución muestra Amazon EKS con dos pods (implementación 1 y implementación 2) y dos grupos de nodos (ng1 y ng2) con dos nodos cada uno. Los pods y los nodos tienen las siguientes propiedades.

 

Pod de implementación 1

Pod de implementación 2

Grupo de nodos 1 (ng1)

Grupo de nodos 2 (ng2)

Tolerancia

clave: classified_load, valor: verdadero, efecto: NoSchedule

clave: machine_learning_workload, valor: verdadero, efecto: NoSchedule

Ninguna

 

 

Afinidad de nodos

clave: alpha.eksctl.io/nodegroup-name = ng1;

Ninguna

NodeGroups.name = ng1

 

Taint

 

 

clave: classified_load, valor: verdadero, efecto: NoSchedule

clave: machine_learning_workload, valor: verdadero, efecto: NoSchedule

Ninguna

Configuración de Amazon EKS con dos pods y dos grupos de nodos.
  1. El pod de implementación 1 tiene definidas las tolerancias y la afinidad de nodos, lo que indica al programador de Kubernetes que coloque los pods de despliegue en los nodos del grupo de nodos 1 (ng1).

  2. El grupo de nodos 2 (ng2) no tiene una etiqueta de nodo que coincida con la expresión del selector de nodos de afinidad de nodos de la implementación 1, por lo que los pods no se programarán en los nodos ng2.

  3. El pod de la implementación 2 no tiene tolerancias ni afinidades de nodos definidas en el manifiesto de implementación. El programador rechazará la programación de pods de implementación 2 en el grupo de nodos 1 debido a las taint de los nodos.

  4. En su lugar, los pods de implementación 2 se colocarán en el grupo de nodos 2, ya que los nodos no tienen ningún taint.

Este patrón muestra que, si se utilizan las taints y las tolerancias, combinadas con la afinidad de nodos, se puede controlar la colocación de los pods en conjuntos específicos de nodos de trabajo.

Herramientas

Servicios de AWS

Otras herramientas

  • Docker es un conjunto de productos de plataforma como servicio (PaaS) que utiliza la virtualización a nivel del sistema operativo para entregar software en contenedores.

  • kubectl: una interfaz de la línea de comandos que le ayuda en la ejecución de comandos en clústeres de Kubernetes.

Epics

TareaDescripciónHabilidades requeridas

Cree el archivo cluster.yaml.

Cree un archivo denominado cluster.yaml con el siguiente código.

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: eks-taint-demo region: us-west-1 # Unmanaged nodegroups with and without taints. nodeGroups: - name: ng1 instanceType: m5.xlarge minSize: 2 maxSize: 3 taints: - key: classified_workload value: "true" effect: NoSchedule - key: machine_learning_workload value: "true" effect: NoSchedule - name: ng2 instanceType: m5.xlarge minSize: 2 maxSize: 3
Propietario de la aplicación, AWS DevOps, administrador de la nube, DevOps ingeniero

Cree el clúster mediante eksctl.

Ejecute el archivo cluster.yaml para crear el clúster EKS. La creación del clúster puede tardar unos minutos.

eksctl create cluster -f cluster.yaml
AWS DevOps, administrador de sistemas de AWS, desarrollador de aplicaciones
TareaDescripciónHabilidades requeridas

Crear un repositorio privado de Amazon ECR.

Para crear un repositorio de Amazon ECR, consulte Creación de un repositorio privado. Anote el URI del repositorio.

AWS DevOps, DevOps ingeniero, desarrollador de aplicaciones

Cree el archivo Dockerfile.

Si tiene una imagen de contenedor de Docker existente que desea usar para probar el patrón, puede omitir este paso.

Para crear un archivo Dockerfile, use el siguiente fragmento como referencia. Si encuentra errores, consulte la sección Resolución de problemas.

FROM adoptopenjdk/openjdk11:jdk-11.0.14.1_1-alpine RUN apk add maven WORKDIR /code # Prepare by downloading dependencies ADD pom.xml /code/pom.xml RUN ["mvn", "dependency:resolve"] RUN ["mvn", "verify"] # Adding source, compile and package into a fat jar ADD src /code/src RUN ["mvn", "package"] EXPOSE 4567 CMD ["java", "-jar", "target/eksExample-jar-with-dependencies.jar"]
AWS DevOps, DevOps ingeniero

Cree el archivo pom.xml y los archivos fuente, y cree y envíe la imagen de Docker.

Para crear el archivo pom.xml y el archivo fuente de Java, consulte Implementar un ejemplo de microservicio Java en el patrón Amazon EKS.

Siga las instrucciones de ese patrón para crear y enviar la imagen de Docker.

AWS DevOps, DevOps ingeniero, desarrollador de aplicaciones
TareaDescripciónHabilidades requeridas

Cree el archivo deployment.yaml.

Para crear el archivo deployment.yaml, use el código que aparece en la sección Información adicional.

En el código, la clave de la afinidad de nodos es cualquier etiqueta que se cree al crear grupos de nodos. Este patrón usa la etiqueta predeterminada creada por eksctl. Para obtener información sobre cómo personalizar las etiquetas, consulte Asignar pods a nodos en la documentación de Kubernetes.

El valor de la clave de afinidad de nodos es el nombre del grupo de nodos creado por cluster.yaml.

Para obtener la clave y el valor de la taint, ejecute el siguiente comando.

kubectl get nodes -o json | jq '.items[].spec.taints'

La imagen es el URI del repositorio de Amazon ECR que creó en un paso anterior.

AWS DevOps, DevOps ingeniero, desarrollador de aplicaciones

Implemente el archivo.

Para implementar en Amazon EKS, ejecute el siguiente comando.

kubectl apply -f deployment.yaml
Desarrollador de aplicaciones, DevOps ingeniero, AWS DevOps

Compruebe la implementación.

  1. Para verificar si los pods están LISTOS, ejecute el siguiente comando.

    kubectl get pods -o wide

    Si el POD está listo, la salida tendrá un aspecto semejante al siguiente, con el STATUS como En ejecución.

    NAME        READY    STATUS    RESTARTS   AGE   IP  NODE  NOMINATED NODE   READINESS GATES <pod_name>   1/1     Running   0          12d   192.168.18.50   ip-192-168-20-110.us-west-1.compute.internal   <none>           <none>

    Anote el nombre del pod y el nombre del nodo. Puede saltar el siguiente paso.

  2. (Opcional) Para obtener detalles adicionales sobre el Pod y verificar las tolerancias en el Pod, ejecute el siguiente comando.

    kubectl describe pod <pod_name>

    Un ejemplo de la salida se encuentra en la sección de Información adicional.

  3. Para validar que la ubicación del pod en el nodo es correcta, ejecute el siguiente comando.

    kubectl describe node <node name> | grep -A 1 "Taints"

    Confirme que la taint del nodo coincide con la tolerancia y que la etiqueta del nodo coincide con la afinidad de nodos definida en deployment.yaml.

    El pod con tolerancias y afinidad de nodos debe colocarse en un nodo con las taint y las etiquetas de afinidad de nodos coincidentes. El comando anterior muestra las taint del nodo. El siguiente es un ejemplo de salida.

    kubectl describe node ip-192-168-29-181.us-west-1.compute.internal | grep -A 1 "Taints" Taints:             classifled_workload=true:NoSchedule                     machine_learning_workload=true:NoSchedule

    Además, ejecute el siguiente comando para comprobar que el nodo en el que está colocado el pod tiene una etiqueta que coincida con la etiqueta del nodo de afinidad de nodos.

    kubectl get node <node name> --show-labels
  4. Para comprobar que la aplicación está haciendo lo que debe hacer, compruebe los registros del Pod ejecutando el siguiente comando.

    kubectl logs -f <name-of-the-pod>
Desarrollador de aplicaciones, DevOps ingeniero, AWS DevOps

Cree un segundo archivo.yaml de implementación sin tolerancias ni afinidad entre nodos.

Este paso adicional sirve para validar que, si no se especifica ninguna afinidad o tolerancia de nodos en el archivo de manifiesto de implementación, el pod resultante no esté programado en un nodo contaminado. (Debe programarse en un nodo que no tenga ninguna taint). Use el siguiente código para crear un nuevo archivo de implementación llamado deploy_no_taint.yaml.

apiVersion: apps/v1 kind: Deployment metadata: name: microservice-deployment-non-tainted spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: java-microservice-no-taint template: metadata: labels: app.kubernetes.io/name: java-microservice-no-taint spec: containers: - name: java-microservice-container-2 image: <account_number>.dkr.ecr<region>.amazonaws.com/<repository_name>:latest ports: - containerPort: 4567
Desarrollador de aplicaciones, AWS DevOps, DevOps ingeniero

Implemente el segundo archivo de implementación (.yaml) y valide la colocación del pod

  1. Ejecute el siguiente comando de la .

    kubectl apply -f deploy_no_taint.yaml
  2. Una vez que la implementación se haya realizado correctamente, ejecute los mismos comandos que ejecutó anteriormente para comprobar la ubicación del pod en un grupo de nodos sin ningún problema.

    kubectl describe node <node_name> | grep "Taints"

    La salida debería ser la siguiente.

    Taints: <none>

    Esto completa la prueba.

Desarrollador de aplicaciones, AWS DevOps, DevOps ingeniero
TareaDescripciónHabilidades requeridas

Limpie los recursos.

Para evitar incurrir en cargos de AWS por los recursos que quedan en ejecución, utilice el siguiente comando.

eksctl delete cluster --name <Name of the cluster> --region <region-code>
AWS DevOps, desarrollador de aplicaciones

Resolución de problemas

ProblemaSolución

Es posible que algunos de estos comandos no se ejecuten si su sistema utiliza la arquitectura arm64 (especialmente si la ejecuta en un Mac M1). La siguiente línea puede generar un error.

FROM adoptopenjdk/openjdk11:jdk-11.0.14.1_1-alpine

Si tiene errores al ejecutar el Dockerfile, sustituya la línea FROM por la siguiente.

FROM bellsoft/liberica-openjdk-alpine-musl:17

Recursos relacionados

Información adicional

deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: microservice-deployment spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: java-microservice template: metadata: labels: app.kubernetes.io/name: java-microservice spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: alpha.eksctl.io/nodegroup-name operator: In values: - <node-group-name-from-cluster.yaml> tolerations: #only this pod has toleration and is viable to go to ng with taint - key: "<Taint key>" #classified_workload in our case operator: Equal value: "<Taint value>" #true effect: "NoSchedule" - key: "<Taint key>" #machine_learning_workload in our case operator: Equal value: "<Taint value>" #true effect: "NoSchedule" containers: - name: java-microservice-container image: <account_number>.dkr.ecr<region>.amazonaws.com/<repository_name>:latest ports: - containerPort: 4567

describe el ejemplo de salida del pod

Name: microservice-deployment-in-tainted-nodes-5684cc495b-vpcfx Namespace: default Priority: 0 Node: ip-192-168-29-181.us-west-1.compute.internal/192.168.29.181 Start Time: Wed, 14 Sep 2022 11:06:47 -0400 Labels: app.kubernetes.io/name=java-microservice-taint pod-template-hash=5684cc495b Annotations: kubernetes.io/psp: eks.privileged Status: Running IP: 192.168.13.44 IPs: IP: 192.168.13.44 Controlled By: ReplicaSet/microservice-deployment-in-tainted-nodes-5684cc495b Containers: java-microservice-container-1: Container ID: docker://5c158df8cc160de8f57f62f3ee16b12725a87510a809d90a1fb9e5d873c320a4 Image: 934188034500.dkr.ecr.us-east-1.amazonaws.com/java-eks-apg Image ID: docker-pullable://934188034500.dkr.ecr.us-east-1.amazonaws.com/java-eks-apg@sha256:d223924aca8315aab20d54eddf3443929eba511b6433017474d01b63a4114835 Port: 4567/TCP Host Port: 0/TCP State: Running Started: Wed, 14 Sep 2022 11:07:02 -0400 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ddvvw (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: kube-api-access-ddvvw: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> Tolerations: classifled_workload=true:NoSchedule machine_learning_workload=true:NoSchedule node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: <none>