Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

27 de abril en la conferencia Huelga 2019, como parte de la sección “DevOps”, se entregó el informe “Autoescalado y gestión de recursos en Kubernetes”. Habla sobre cómo puede utilizar K8 para garantizar una alta disponibilidad de sus aplicaciones y garantizar el máximo rendimiento.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Por tradición, nos complace presentarles vídeo del informe (44 minutos, mucho más informativo que el artículo) y el resumen principal en forma de texto. ¡Ir!

Analicemos el tema del informe palabra por palabra y comencemos desde el final.

Kubernetes

Digamos que tenemos contenedores Docker en nuestro host. ¿Para qué? Para garantizar la repetibilidad y el aislamiento, lo que a su vez permite una implementación buena y sencilla, CI/CD. Disponemos de muchos vehículos de este tipo con contenedores.

¿Qué aporta Kubernetes en este caso?

  1. Dejamos de pensar en estas máquinas y empezamos a trabajar con la “nube” grupo de contenedores o vainas (grupos de contenedores).
  2. Además, ni siquiera pensamos en grupos individuales, sino que gestionamos másоgrupos más grandes. Semejante primitivos de alto nivel Permítanos decir que existe una plantilla para ejecutar una determinada carga de trabajo y aquí está la cantidad requerida de instancias para ejecutarla. Si posteriormente cambiamos la plantilla, todas las instancias cambiarán.
  3. Con API declarativa En lugar de ejecutar una secuencia de comandos específicos, describimos la "estructura del mundo" (en YAML), que es creada por Kubernetes. Y nuevamente: cuando la descripción cambia, su visualización real también cambiará.

Administracion de recursos

CPU

Ejecutemos nginx, php-fpm y mysql en el servidor. En realidad, estos servicios tendrán aún más procesos en ejecución, cada uno de los cuales requiere recursos informáticos:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)
(los números en la diapositiva son "loros", la necesidad abstracta de cada proceso de potencia informática)

Para que sea más fácil trabajar con esto, es lógico combinar procesos en grupos (por ejemplo, todos los procesos nginx en un grupo "nginx"). Una forma sencilla y obvia de hacer esto es poner cada grupo en un contenedor:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Para continuar, debes recordar qué es un contenedor (en Linux). Su aparición fue posible gracias a tres características clave del kernel, implementadas hace bastante tiempo: capacidades, espacios de nombres и cgrupos. Y el desarrollo adicional se vio facilitado por otras tecnologías (incluidos "shells" convenientes como Docker):

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

En el contexto del informe, sólo nos interesa cgrupos, porque los grupos de control son la parte de la funcionalidad de los contenedores (Docker, etc.) que implementa la gestión de recursos. Los procesos combinados en grupos, como queríamos, son grupos de control.

Volvamos a los requisitos de CPU para estos procesos, y ahora para grupos de procesos:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)
(Repito que todos los números son una expresión abstracta de la necesidad de recursos)

Al mismo tiempo, la propia CPU tiene un determinado recurso finito. (en el ejemplo esto es 1000), que a todos les puede faltar (la suma de las necesidades de todos los grupos es 150+850+460=1460). ¿Qué pasará en este caso?

El kernel comienza a distribuir recursos y lo hace “de manera justa”, dando la misma cantidad de recursos a cada grupo. Pero en el primer caso, hay más de los necesarios (333>150), por lo que el exceso (333-150=183) queda en reserva, que también se distribuye equitativamente entre otros dos contenedores:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Como resultado: el primer contenedor tenía suficientes recursos, el segundo no tenía suficientes recursos, el tercero no tenía suficientes recursos. Este es el resultado de acciones. Programador "honesto" en Linux - CFS. Su funcionamiento se puede ajustar mediante la asignación pesos cada uno de los contenedores. Por ejemplo, así:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Veamos el caso de falta de recursos en el segundo contenedor (php-fpm). Todos los recursos del contenedor se distribuyen equitativamente entre los procesos. Como resultado, el proceso maestro funciona bien, pero todos los trabajadores se ralentizan y reciben menos de la mitad de lo que necesitan:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Así es como funciona el programador CFS. Además llamaremos a los pesos que asignamos a los contenedores. peticiones. ¿Por qué es así? Ver más.

Miremos toda la situación desde el otro lado. Como sabes, todos los caminos llevan a Roma y, en el caso de un ordenador, a la CPU. Una CPU, muchas tareas: necesitas un semáforo. La forma más sencilla de gestionar los recursos es el “semáforo”: le daban a un proceso un tiempo de acceso fijo a la CPU, luego al siguiente, etc.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Este enfoque se llama cuotas estrictas. (limitación dura). Recordémoslo simplemente como límites. Sin embargo, si distribuye límites a todos los contenedores, surge un problema: mysql estaba conduciendo por el camino y en algún momento terminó su necesidad de CPU, pero todos los demás procesos se ven obligados a esperar hasta que la CPU inactivo.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Volvamos al kernel de Linux y su interacción con la CPU: el panorama general es el siguiente:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

cgroup tiene dos configuraciones; esencialmente, estos son dos "giros" simples que le permiten determinar:

  1. El peso del contenedor (solicitudes) es las acciones;
  2. El porcentaje del tiempo total de CPU para trabajar en tareas de contenedor (límites) es cuota.

¿Cómo medir la CPU?

Hay diferentes maneras:

  1. ¿Qué loros, nadie lo sabe: es necesario negociar siempre.
  2. Intereses Más claro, pero relativo: el 50% de un servidor con 4 núcleos y con 20 núcleos son cosas completamente diferentes.
  3. Puedes usar los ya mencionados. pesos, que Linux conoce, pero también son relativos.
  4. La opción más adecuada es medir los recursos informáticos en segundos. Aquellos. en segundos de tiempo de procesador en relación con segundos de tiempo real: se dio 1 segundo de tiempo de procesador por 1 segundo real; este es un núcleo de CPU completo.

Para que fuera aún más fácil hablar, comenzaron a medir directamente en granos, es decir, el mismo tiempo de CPU en relación con el real. Dado que Linux entiende los pesos, pero no tanto el tiempo/núcleos de la CPU, se necesitaba un mecanismo para traducir de uno a otro.

Consideremos un ejemplo simple con un servidor con 3 núcleos de CPU, donde a tres pods se les asignarán pesos (500, 1000 y 1500) que se convierten fácilmente en las partes correspondientes de los núcleos asignados a ellos (0,5, 1 y 1,5).

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Si toma un segundo servidor, donde habrá el doble de núcleos (6), y coloca los mismos pods allí, la distribución de núcleos se puede calcular fácilmente simplemente multiplicando por 2 (1, 2 y 3, respectivamente). Pero un momento importante llega cuando aparece un cuarto pod en este servidor, cuyo peso, por conveniencia, será 3000. Quita parte de los recursos de la CPU (la mitad de los núcleos), y para los pods restantes se recalculan (se dividen a la mitad):

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Kubernetes y recursos de CPU

En Kubernetes, los recursos de la CPU generalmente se miden en miliadrax, es decir. Se toman 0,001 núcleos como peso base. (Lo mismo en la terminología de Linux/cgroups se llama CPU compartida, aunque, más precisamente, 1000 milicores = 1024 CPU compartidas). K8s garantiza que no coloque más pods en el servidor que recursos de CPU para la suma de los pesos de todos los pods.

¿Como sucedió esto? Cuando agrega un servidor a un clúster de Kubernetes, se informa cuántos núcleos de CPU tiene disponibles. Y al crear un nuevo pod, el programador de Kubernetes sabe cuántos núcleos necesitará este pod. De esta forma, el pod se asignará a un servidor donde haya suficientes núcleos.

Lo que sucederá si no ¿Se especifica la solicitud (es decir, el pod no tiene una cantidad definida de núcleos que necesita)? Averigüemos cómo Kubernetes generalmente cuenta los recursos.

Para un pod, puede especificar tanto solicitudes (programador CFS) como límites (¿recuerda el semáforo?):

  • Si se especifican iguales, al pod se le asigna una clase de QoS. garantia. Este número de núcleos siempre disponibles está garantizado.
  • Si la solicitud es inferior al límite: clase QoS rompible. Aquellos. Esperamos que un pod, por ejemplo, siempre use 1 núcleo, pero este valor no es una limitación para ello: a veces pod puede usar más (cuando el servidor tiene recursos libres para esto).
  • También hay una clase QoS. mejor esfuerzo — incluye aquellos mismos pods para los cuales no se especifica la solicitud. Los recursos se les dan al final.

Память

Con la memoria, la situación es similar, pero ligeramente diferente; después de todo, la naturaleza de estos recursos es diferente. En general, la analogía es la siguiente:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Veamos cómo se implementan las solicitudes en la memoria. Deje que los pods vivan en el servidor, cambiando el consumo de memoria, hasta que uno de ellos crezca tanto que se quede sin memoria. En este caso, aparece el asesino OOM y mata el proceso más grande:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Esto no siempre nos conviene, por lo que es posible regular qué procesos son importantes para nosotros y no debemos eliminar. Para hacer esto, use el parámetro oom_score_adj.

Volvamos a las clases de QoS de la CPU y hagamos una analogía con los valores de oom_score_adj que determinan las prioridades de consumo de memoria para los pods:

  • El valor más bajo de oom_score_adj para un pod (-998) significa que dicho pod debe eliminarse en último lugar, esto garantia.
  • El más alto - 1000 - es mejor esfuerzo, estas vainas se matan primero.
  • Para calcular los valores restantes (rompible) existe una fórmula, cuya esencia se reduce al hecho de que cuantos más recursos haya solicitado una cápsula, es menos probable que la maten.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

El segundo "giro" - límite_en_bytes - por límites. Con él todo es más sencillo: simplemente asignamos la cantidad máxima de memoria liberada, y aquí (a diferencia de la CPU) no hay duda de cómo medirla (memoria).

En total

Cada pod en Kubernetes recibe requests и limits - ambos parámetros para CPU y memoria:

  1. en función de las solicitudes, funciona el programador de Kubernetes, que distribuye pods entre servidores;
  2. en función de todos los parámetros, se determina la clase de QoS del pod;
  3. Los pesos relativos se calculan en función de las solicitudes de CPU;
  4. el programador CFS se configura en función de las solicitudes de la CPU;
  5. OOM Killer se configura en función de las solicitudes de memoria;
  6. se configura un “semáforo” según los límites de la CPU;
  7. Según los límites de memoria, se configura un límite para el cgroup.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

En general, esta imagen responde a todas las preguntas sobre cómo se produce la parte principal de la gestión de recursos en Kubernetes.

Autoescalado

Escalador automático de clústeres K8s

Imaginemos que todo el clúster ya está ocupado y es necesario crear un nuevo pod. Si bien el pod no puede aparecer, se bloquea en el estado Pendiente. Para que aparezca, podemos conectar un nuevo servidor al cluster o... instalar cluster-autoscaler, que lo hará por nosotros: solicitar una máquina virtual al proveedor de la nube (mediante una solicitud API) y conectarla al cluster. , después de lo cual se agregará el pod .

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Este es el escalado automático del clúster de Kubernetes, que funciona muy bien (según nuestra experiencia). Sin embargo, como en otros lugares, aquí hay algunos matices...

Mientras aumentamos el tamaño del clúster, todo estaba bien, pero ¿qué sucede cuando el clúster comenzó a liberarse? El problema es que migrar pods (para liberar hosts) es técnicamente muy difícil y costoso en términos de recursos. Kubernetes utiliza un enfoque completamente diferente.

Considere un grupo de 3 servidores que tiene implementación. Tiene 6 pods: ahora hay 2 para cada servidor. Por alguna razón queríamos apagar uno de los servidores. Para ello usaremos el comando kubectl drain, cual:

  • prohibirá el envío de nuevos pods a este servidor;
  • eliminará los pods existentes en el servidor.

Dado que Kubernetes es responsable de mantener el número de pods (6), simplemente recreará en otros nodos, pero no en el que está deshabilitado, ya que ya está marcado como no disponible para alojar nuevos pods. Esta es una mecánica fundamental para Kubernetes.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Sin embargo, aquí también hay un matiz. En una situación similar, para StatefulSet (en lugar de Deployment), las acciones serán diferentes. Ahora ya tenemos una aplicación con estado, por ejemplo, tres pods con MongoDB, uno de los cuales tiene algún tipo de problema (los datos se han dañado u otro error que impide que el pod se inicie correctamente). Y nuevamente decidimos deshabilitar un servidor. ¿Lo que sucederá?

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

MongoDB podría muere porque necesita quórum: para un grupo de tres instalaciones, al menos dos deben funcionar. Sin embargo, esto no esta pasando - gracias a PodDisruptionPresupuesto. Este parámetro determina el número mínimo requerido de pods de trabajo. Saber que uno de los pods de MongoDB ya no funciona y ver que PodDisruptionBudget está configurado para MongoDB minAvailable: 2, Kubernetes no le permitirá eliminar un pod.

En pocas palabras: para que el movimiento (y, de hecho, la recreación) de pods funcione correctamente cuando se lanza el clúster, es necesario configurar PodDisruptionBudget.

Escalado horizontal

Consideremos otra situación. Hay una aplicación ejecutándose como implementación en Kubernetes. El tráfico de usuarios llega a sus pods (por ejemplo, hay tres) y en ellos medimos un determinado indicador (por ejemplo, la carga de la CPU). Cuando la carga aumenta, la registramos según un cronograma y aumentamos la cantidad de pods para distribuir las solicitudes.

Hoy en día en Kubernetes esto no es necesario hacerlo manualmente: se configura un aumento/disminución automática en el número de pods dependiendo de los valores de los indicadores de carga medidos.

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Las principales preguntas aquí son: qué medir exactamente и como interpretar valores obtenidos (para tomar una decisión sobre cambiar el número de pods). Puedes medir mucho:

Autoescalado y gestión de recursos en Kubernetes (revisión y reportaje en vídeo)

Cómo hacer esto técnicamente: recopilar métricas, etc. — Hablé detalladamente en el informe sobre Monitoreo y Kubernetes. Y el principal consejo para elegir los parámetros óptimos es experimento!

Hay método de uso (Saturación de utilización y errores), cuyo significado es el siguiente. ¿Sobre qué base tiene sentido escalar, por ejemplo, php-fpm? Basado en el hecho de que los trabajadores se están acabando, esto es utilización. Y si se acaban los trabajadores y no se aceptan nuevas conexiones, esto ya es saturación. Es necesario medir ambos parámetros y, dependiendo de los valores, realizar un escalado.

En lugar de una conclusión

El informe tiene una continuación: sobre el escalamiento vertical y cómo seleccionar los recursos adecuados. Hablaré de esto en futuros videos en nuestro youtube - suscríbete para no perdértelo!

Vídeos y diapositivas

Vídeo de la actuación (44 minutos):

Presentación del informe:

PS

Otros informes sobre Kubernetes en nuestro blog:

Fuente: habr.com

Añadir un comentario