Computación y escalado automático - Amazon EKS

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.

Computación y escalado automático

Como desarrollador, harás estimaciones sobre las necesidades de recursos de tu aplicación, por ejemplo, de CPU y memoria, pero si no las ajustas continuamente, es posible que queden anticuadas, lo que podría aumentar tus costes y empeorar el rendimiento y la fiabilidad. Es más importante ajustar continuamente los requisitos de recursos de una aplicación que hacerlos bien la primera vez.

Las mejores prácticas que se mencionan a continuación le ayudarán a crear y operar cargas de trabajo rentables que logren resultados empresariales y, al mismo tiempo, minimicen los costos y permitan a su organización maximizar el retorno de la inversión. Un orden de importancia de alto nivel para optimizar los costos de cómputo de los clústeres es:

  1. Cargas de trabajo del tamaño correcto

  2. Reduzca la capacidad no utilizada

  3. Optimice los tipos de capacidad de cómputo (por ejemplo, Spot) y los aceleradores (por ejemplo GPUs)

Dimensione sus cargas de trabajo de forma adecuada

En la mayoría de los clústeres de EKS, la mayor parte del costo proviene de las EC2 instancias que se utilizan para ejecutar las cargas de trabajo en contenedores. No podrá dimensionar correctamente sus recursos informáticos sin comprender los requisitos de sus cargas de trabajo. Por este motivo, es esencial que utilice las solicitudes y los límites adecuados y que realice los ajustes necesarios en esos ajustes. Además, las dependencias, como el tamaño de la instancia y la selección del almacenamiento, pueden afectar al rendimiento de la carga de trabajo, lo que puede tener diversas consecuencias imprevistas en los costes y la fiabilidad.

Las solicitudes deben ajustarse a la utilización real. Si las solicitudes de un contenedor son demasiado altas, habrá capacidad no utilizada, lo que constituye un factor importante en los costos totales del clúster. Cada contenedor de un módulo, por ejemplo, una aplicación o un sidecar, debe tener sus propias solicitudes y límites establecidos para garantizar que los límites totales de los módulos sean lo más precisos posible.

Utilice herramientas como Goldilocks, KRR y Kubecost, que calculan las solicitudes de recursos y los límites de sus contenedores. En función de la naturaleza de las aplicaciones, los requisitos de rendimiento y coste y la complejidad, es necesario evaluar qué métricas son las mejores para escalar, en qué punto se degrada el rendimiento de las aplicaciones (punto de saturación) y cómo ajustar las solicitudes y los límites en consecuencia. Consulte el artículo sobre el tamaño correcto de las aplicaciones para obtener más información sobre este tema.

Recomendamos usar el escalador automático de pods horizontales (HPA) para controlar cuántas réplicas de la aplicación deben ejecutarse, el escalador automático de pods verticales (VPA) para ajustar el número de solicitudes y los límites que la aplicación necesita por réplica, y un escalador automático de nodos como Karpenter o Cluster Autoscaler para ajustar continuamente el número total de nodos del clúster. Las técnicas de optimización de costos que utilizan Karpenter y Cluster Autoscaler se documentan en una sección posterior de este documento.

El escalador automático Vertical Pod puede ajustar las solicitudes y los límites asignados a los contenedores para que las cargas de trabajo se ejecuten de manera óptima. Debe ejecutar el VPA en modo de auditoría para que no realice cambios automáticamente ni reinicie los pods. Sugerirá cambios en función de las métricas observadas. Si se producen cambios que afecten a las cargas de trabajo de producción, primero debe revisarlos y probarlos en un entorno que no sea de producción, ya que pueden afectar a la fiabilidad y el rendimiento de la aplicación.

Reduzca el consumo

La mejor forma de ahorrar dinero es aprovisionar menos recursos. Una forma de hacerlo es ajustar las cargas de trabajo en función de sus requisitos actuales. Debe comenzar cualquier esfuerzo de optimización de costos asegurándose de que sus cargas de trabajo definan sus requisitos y escalen de forma dinámica. Para ello, será necesario obtener las métricas de las aplicaciones y configurar configuraciones (por ejemplo, Pod Readiness Gates) para garantizar que la aplicación pueda ampliarse y reducirse de forma dinámica y segura. PodDisruptionBudgets Es importante tener en cuenta que las restricciones PodDisruptionBudgets pueden impedir que Cluster Autoscaler y Karpenter reduzcan la escala de los nodos, ya que tanto Cluster Autoscaler como Karpenter respetan. PodDisruptionBudgets El valor «minAvailable» en el campo «minAvailable» siempre PodDisruptionBudget debe ser inferior al número de pods de la implementación y se debe mantener una buena separación entre ambos, por ejemplo, en un despliegue de 6 pods en el que desee tener un mínimo de 4 pods en funcionamiento en todo momento, establezca el valor «minAvailable» en 4. PodDisruptionBidget Esto permitirá que Cluster Autoscaler y Karpenter drenen y desalojen de forma segura los pods de los nodos infrautilizados durante un evento de reducción de escala de nodos. Consulte el documento de preguntas frecuentes sobre Cluster Autoscaler.

El escalador automático horizontal Pod es un escalador automático de cargas de trabajo flexible que puede ajustar el número de réplicas que se necesitan para cumplir con los requisitos de rendimiento y confiabilidad de su aplicación. Cuenta con un modelo flexible para definir cuándo escalar hacia arriba y hacia abajo en función de varias métricas, como la CPU o la memoria, o métricas personalizadas, por ejemplo, la profundidad de la cola, el número de conexiones a un pod, etc.

El Kubernetes Metrics Server permite el escalado en respuesta a métricas integradas, como el uso de la CPU y la memoria, pero si quieres escalar en función de otras métricas, como la profundidad de colas de Amazon CloudWatch o SQS, deberías considerar proyectos de escalado automático basados en eventos, como KEDA. Consulte esta entrada de blog sobre cómo utilizar KEDA con las métricas. CloudWatch Si no está seguro de qué métricas debe monitorizar y en qué base escalar, consulte las mejores prácticas de monitorización de las métricas más importantes.

Reducir el consumo de carga de trabajo crea un exceso de capacidad en un clúster y, con una configuración de escalado automático adecuada, puede reducir los nodos automáticamente y reducir el gasto total. Le recomendamos que no intente optimizar la capacidad de cómputo manualmente. El programador de Kubernetes y los escaladores automáticos de nodos se diseñaron para gestionar este proceso por ti.

Reduzca la capacidad no utilizada

Una vez que haya determinado el tamaño correcto de las aplicaciones y reduzca el exceso de solicitudes, puede empezar a reducir la capacidad informática aprovisionada. Debería poder hacerlo de forma dinámica si se ha tomado el tiempo necesario para dimensionar correctamente sus cargas de trabajo según las secciones anteriores. Hay dos escaladores automáticos de nodos principales que se utilizan con Kubernetes en AWS.

Karpenter y Cluster Autoscaler

Tanto Karpenter como el escalador automático de clústeres de Kubernetes escalarán la cantidad de nodos del clúster a medida que se creen o eliminen los pods y cambien los requisitos de procesamiento. El objetivo principal de ambos es el mismo, pero Karpenter adopta un enfoque diferente para la administración de nodos, el aprovisionamiento y el desaprovisionamiento, lo que puede ayudar a reducir los costos y optimizar el uso en todo el clúster.

A medida que los clústeres aumentan de tamaño y la variedad de cargas de trabajo, se hace más difícil configurar previamente los grupos de nodos y las instancias. Al igual que ocurre con las solicitudes de carga de trabajo, es importante establecer un punto de referencia inicial y ajustarlo continuamente según sea necesario.

Si utiliza Cluster AutoScaler, respetará los valores «mínimo» y «máximo» de cada grupo de Auto Scaling (ASG) y solo ajustará el valor «deseado». Es importante prestar atención al establecer estos valores para el ASG subyacente, ya que Cluster Autoscaler no podrá reducir un ASG más allá de su recuento «mínimo». Defina el recuento «deseado» como el número de nodos que necesita durante el horario laboral normal y «mínimo» como el número de nodos que necesita fuera del horario laboral. Consulte el documento de preguntas frecuentes sobre Cluster Autoscaler.

Expansor prioritario de escalador automático de clústeres

El escalador automático de clústeres de Kubernetes funciona escalando grupos de nodos (denominados grupo de nodos) hacia arriba y hacia abajo a medida que las aplicaciones se escalan hacia arriba y hacia abajo. Si no escala las cargas de trabajo de forma dinámica, el escalador automático de clústeres no le ayudará a ahorrar dinero. El escalador automático de clústeres requiere que un administrador de clústeres cree grupos de nodos con antelación para que las cargas de trabajo se consuman. Los grupos de nodos deben configurarse para usar instancias que tengan el mismo «perfil», es decir, aproximadamente la misma cantidad de CPU y memoria.

Puede tener varios grupos de nodos y el escalador automático de clústeres se puede configurar para establecer niveles de escalado prioritarios, y cada grupo de nodos puede contener nodos de diferentes tamaños. Los grupos de nodos pueden tener diferentes tipos de capacidad y el expansor de prioridad se puede usar para escalar primero los grupos menos costosos.

A continuación, se muestra un ejemplo de un fragmento de configuración de clúster que utiliza ConfigMap` a para priorizar la capacidad reservada antes de usar instancias bajo demanda. Puede utilizar la misma técnica para dar prioridad a las instancias Graviton o puntual frente a otros tipos.

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: my-cluster managedNodeGroups: - name: managed-ondemand minSize: 1 maxSize: 7 instanceType: m5.xlarge - name: managed-reserved minSize: 2 maxSize: 10 instanceType: c5.2xlarge
apiVersion: v1 kind: ConfigMap metadata: name: cluster-autoscaler-priority-expander namespace: kube-system data: priorities: |- 10: - .*ondemand.* 50: - .*reserved.*

El uso de grupos de nodos puede ayudar a los recursos informáticos subyacentes a cumplir lo esperado de forma predeterminada, es decir, distribuir los nodos entre sí AZs, pero no todas las cargas de trabajo tienen los mismos requisitos o expectativas, por lo que es mejor dejar que las aplicaciones declaren sus requisitos de forma explícita. Para obtener más información sobre el escalador automático de clústeres, consulta la sección de prácticas recomendadas.

Desprogramador

El escalador automático de clústeres puede añadir y eliminar la capacidad de los nodos de un clúster en función de la necesidad de programar nuevos pods o de la infrautilización de los nodos. No adopta una visión holística de la ubicación de los pods una vez que se han programado en un nodo. Si utiliza el escalador automático de clústeres, también debería utilizar el desprogramador de Kubernetes para evitar desperdiciar capacidad en su clúster.

Si tiene 10 nodos en un clúster y cada nodo se utiliza en un 60%, no está utilizando el 40% de la capacidad aprovisionada en el clúster. Con el escalador automático de clústeres, puede establecer el umbral de utilización por nodo en un 60%, pero solo intentará reducir la escala de un nodo si la utilización cayera por debajo del 60%.

Con el desprogramador, puede analizar la capacidad y la utilización del clúster una vez que se hayan programado los pods o se hayan agregado nodos al clúster. Intenta mantener la capacidad total del clúster por encima de un umbral específico. También puede eliminar los pods en función de la contaminación de los nodos o de los nuevos nodos que se unan al clúster para garantizar que los pods se ejecuten en su entorno informático óptimo. Ten en cuenta que el desprogramador no programa el reemplazo de los pods desalojados, sino que se basa en el programador predeterminado para ello.

Consolidación de Karpenter

Karpenter adopta un enfoque «sin grupos» para la gestión de nodos. Este enfoque es más flexible para los diferentes tipos de carga de trabajo y requiere una configuración inicial menor para los administradores de clústeres. En lugar de predefinir los grupos y escalar cada grupo según las necesidades de las cargas de trabajo, Karpenter utiliza aprovisionadores y plantillas de nodos para definir en términos generales qué tipo de EC2 instancias se pueden crear y la configuración de las instancias a medida que se crean.

El empaquetado en contenedores es la práctica de utilizar más recursos de la instancia, agrupando más cargas de trabajo en un menor número de instancias con un tamaño óptimo. Si bien esto ayuda a reducir los costos de procesamiento al aprovisionar únicamente los recursos que utilizan sus cargas de trabajo, tiene su contrapartida. El inicio de nuevas cargas de trabajo puede tardar más tiempo, ya que hay que añadir capacidad al clúster, especialmente durante eventos de gran escalado. Tenga en cuenta el equilibrio entre la optimización de costos, el rendimiento y la disponibilidad al configurar el embalaje en contenedores.

Karpenter puede monitorear y empaquetar archivos de forma continua para mejorar la utilización de los recursos de las instancias y reducir los costos de procesamiento. Karpenter también puede seleccionar un nodo de trabajadores más rentable para su carga de trabajo. Esto se puede lograr activando el indicador de «consolidación» en true en el aprovisionador (véase un fragmento de código de ejemplo a continuación). El siguiente ejemplo muestra un ejemplo de aprovisionador que permite la consolidación. En el momento de escribir esta guía, Karpenter no sustituirá una instancia de Spot en ejecución por una instancia de Spot más económica. Para obtener más información sobre la consolidación de Karpenter, consulta este blog.

apiVersion: karpenter.sh/v1 kind: Provisioner metadata: name: enable-binpacking spec: consolidation: enabled: true

En el caso de cargas de trabajo que podrían no ser interrumpibles, por ejemplo, trabajos por lotes de larga duración sin puntos de control, considere la posibilidad de anotar los módulos con esa anotación. do-not-evict Al optar por no desalojar los módulos, le estás diciendo a Karpenter que no debe eliminar voluntariamente los nodos que contengan este módulo. Sin embargo, si se do-not-evict añade un módulo a un nodo mientras éste se está vaciando, los módulos restantes se seguirán desalojando, pero ese módulo bloqueará la terminación hasta que se elimine. En cualquier caso, se acordonará el nodo para evitar que se programen trabajos adicionales en el nodo. A continuación se muestra un ejemplo que muestra cómo configurar la anotación:

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "karpenter.sh/do-not-evict": "true" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80

Elimine los nodos infrautilizados ajustando los parámetros del escalador automático del clúster

La utilización de los nodos se define como la suma de los recursos solicitados dividida por la capacidad. De forma predeterminada, scale-down-utilization-threshold se establece en el 50%. Este parámetro se puede usar junto con yscale-down-unneeded-time, que determina cuánto tiempo no se necesitará un nodo antes de que pueda ser reducido; el valor predeterminado es de 10 minutos. Kube-scheduler programará los pods que sigan ejecutándose en un nodo reducido en otros nodos. Ajustar esta configuración puede ayudar a eliminar los nodos que están infrautilizados, pero es importante que primero pruebes estos valores para no forzar al clúster a reducir su escala prematuramente.

Para evitar que se produzca una reducción de tamaño, asegúrese de que los módulos cuyo desalojo resulta caro estén protegidos por una etiqueta reconocida por el escalador automático de clústeres. Para ello, asegúrese de que los módulos cuyo desalojo resulta caro tengan la anotación correspondiente. cluster-autoscaler.kubernetes.io/safe-to-evict=false A continuación se muestra un ejemplo de yaml para configurar la anotación:

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80