paint-brush
Cómo reducir los costos a través del empaquetado de clústeres densos de Google Kubernetes Engine (GKE)por@arslanbekov
459 lecturas
459 lecturas

Cómo reducir los costos a través del empaquetado de clústeres densos de Google Kubernetes Engine (GKE)

por Arslabekov Denis5m2023/02/21
Read on Terminal Reader

Demasiado Largo; Para Leer

Tenemos más de cinco entornos de prueba permanentes y estamos implementando entornos para desarrolladores a pedido. El número de módulos entre semana alcanza los 5000 durante el día y sigue creciendo. El pod del servidor de métricas estaba experimentando un error de falta de memoria (OOM) y un error grave en los registros. La razón estaba en los límites de los recursos de la cápsula.
featured image - Cómo reducir los costos a través del empaquetado de clústeres densos de Google Kubernetes Engine (GKE)
Arslabekov Denis HackerNoon profile picture
0-item

¡Saludos a todos! Hoy nos gustaría compartir nuestra experiencia con Google Kubernetes Engine para administrar nuestros clústeres de Kubernetes. Lo hemos estado usando durante los últimos tres años en producción y nos complace que ya no tengamos que preocuparnos por administrar estos clústeres nosotros mismos.


Actualmente, tenemos todos nuestros entornos de prueba y clústeres de infraestructura únicos bajo el control de Kubernetes. Hoy, queremos hablar sobre cómo encontramos un problema en nuestro grupo de prueba y cómo esperamos que este artículo ahorre tiempo y esfuerzo a otros.


Debemos proporcionar información sobre nuestra infraestructura de prueba para comprender completamente nuestro problema. Tenemos más de cinco entornos de prueba permanentes y estamos implementando entornos para desarrolladores a pedido. El número de módulos entre semana alcanza los 6000 durante el día y sigue creciendo. Dado que la carga es inestable, empaquetamos los módulos muy apretados para ahorrar costos, y la reventa de recursos es nuestra mejor estrategia.

Notificación de holgura KubeAPIErrorsHigh de producción


Esta configuración funcionó bien para nosotros hasta que un día recibimos una alerta y no pudimos eliminar un espacio de nombres. El mensaje de error que recibimos con respecto a la eliminación del espacio de nombres fue:

 $ kubectl delete namespace arslanbekov Error from server (Conflict): Operation cannot be fulfilled on namespaces "arslanbekov": The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system.


Incluso el uso de la opción de eliminación forzada no resolvió el problema:

 $ kubectl get namespace arslanbekov -o yaml apiVersion: v1 kind: Namespace metadata: ... spec: finalizers: - kubernetes status: phase: Terminating


Para resolver el problema del espacio de nombres atascado, seguimos una guía . Aún así, esta solución temporal no era la ideal, ya que nuestros desarrolladores deberían haber podido crear y eliminar sus entornos a voluntad, utilizando la abstracción del espacio de nombres.


Decididos a encontrar una solución mejor, decidimos investigar más a fondo. La alerta indicó un problema de métricas, que confirmamos ejecutando un comando:

 $ kubectl api-resources --verbs=list --namespaced -o name error: unable to retrieve the complete list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to handle the request


Descubrimos que el pod del servidor de métricas estaba experimentando un error de falta de memoria (OOM) y un error grave en los registros:


 apiserver panic'd on GET /apis/metrics.k8s.io/v1beta1/nodes: killing connection/stream because serving request timed out and response had been started goroutine 1430 [running]:


La razón estaba en los límites de los recursos del pod:

El contenedor estaba encontrando estos problemas debido a su definición, que era la siguiente (bloque de límites):

 resources: limits: cpu: 51m memory: 123Mi requests: cpu: 51m memory: 123Mi


El problema era que al contenedor se le asignaron solo 51 millones de CPU , lo que equivale aproximadamente a 0,05 de una CPU de un núcleo , y esto no fue suficiente para manejar las métricas de una cantidad tan grande de pods. Principalmente se utiliza el programador CFS.


Por lo general, solucionar estos problemas es sencillo e implica simplemente asignar más recursos al pod. Sin embargo, en GKE, esta opción no está disponible en la interfaz de usuario ni a través de la CLI de gcloud. Esto se debe a que Google protege los recursos del sistema para que no se modifiquen, lo cual es comprensible teniendo en cuenta que toda la administración se realiza por su parte.


Descubrimos que no éramos los únicos que enfrentamos este problema y encontramos un problema similar en el que el autor intentó cambiar la definición del pod manualmente. Él tuvo éxito, pero nosotros no. Cuando intentamos cambiar los límites de recursos en el archivo YAML, GKE los revirtió rápidamente.


Necesitábamos encontrar otra solución.


Nuestro primer paso fue comprender por qué los límites de recursos se establecieron en estos valores. El pod constaba de dos contenedores: el metrics-server y el addon-resizer . Este último era responsable de ajustar los recursos a medida que se agregaban o eliminaban nodos del clúster, actuando como un cuidador de la escala automática vertical del clúster.


Su definición de línea de comando era la siguiente:

 command: - /pod_nanny - --config-dir=/etc/config - --cpu=40m - --extra-cpu=0.5m - --memory=35Mi - --extra-memory=4Mi ...


En esta definición, la CPU y la memoria representan los recursos básicos, mientras que extra-cpu y extra-memory representan recursos adicionales por nodo. Los cálculos para 180 nodos serían los siguientes:

 0.5m * 180 + 40m=~130m


La misma lógica se aplica a los recursos de memoria.

Desafortunadamente, la única forma de aumentar los recursos era agregando más nodos, lo que no queríamos hacer. Entonces, decidimos explorar otras opciones.


A pesar de no poder resolver el problema por completo, queríamos estabilizar la implementación lo más rápido posible . Aprendimos que algunas propiedades en la definición de YAML se podían cambiar sin que GKE las revirtiera. Para abordar esto, aumentamos la cantidad de réplicas de 1 a 5 , agregamos una verificación de estado y ajustamos la estrategia de implementación de acuerdo con este artículo .


Estas acciones ayudaron a reducir la carga en la instancia del servidor de métricas y garantizaron que siempre tuviéramos al menos un módulo de trabajo que pudiera proporcionar métricas. Nos tomamos un tiempo para reconsiderar el problema y refrescar nuestros pensamientos. La solución terminó siendo simple y obvia en retrospectiva.


Profundizamos en los aspectos internos de addon-resizer y descubrimos que se podía configurar a través de un archivo de configuración y parámetros de línea de comandos. A primera vista, parecía que los parámetros de la línea de comandos deberían anular los valores de configuración, pero no fue así.


Al investigar, encontramos que el archivo de configuración estaba conectado al pod a través de los parámetros de la línea de comando del contenedor addon-resizer:

 --config-dir=/etc/config


El archivo de configuración se asignó como un ConfigMap con el nombre metrics-server-config en el espacio de nombres del sistema, ¡y GKE no revierte esta configuración!


Agregamos recursos a través de esta configuración de la siguiente manera:

 apiVersion: v1 data: NannyConfiguration: |- apiVersion: nannyconfig/v1alpha1 kind: NannyConfiguration baseCPU: 100m cpuPerNode: 5m baseMemory: 100Mi memoryPerNode: 5Mi kind: ConfigMap metadata:


¡Y funcionó! Esto fue una victoria para nosotros.


Dejamos dos pods con comprobaciones de estado y una estrategia de tiempo de inactividad cero mientras se redimensionaba el clúster, y no recibimos más alertas después de realizar estos cambios.


Conclusiones

  1. Es posible que encuentre problemas con el pod del servidor de métricas si tiene un clúster de GKE densamente empaquetado. Los recursos predeterminados asignados al pod pueden no ser suficientes si la cantidad de pods por nodo está cerca del límite (110 por nodo).
  2. GKE protege los recursos de su sistema, incluidos los módulos del sistema, y es imposible controlarlos directamente. Sin embargo, a veces es posible encontrar una solución.
  3. Es importante tener en cuenta que no hay garantía de que la solución siga funcionando después de futuras actualizaciones. Solo hemos encontrado estos problemas en nuestros entornos de prueba, donde tenemos una estrategia de sobreventa de recursos, por lo que, si bien es frustrante, aún podemos administrarlo.