Planifica para la escalabilidad.


En esta página, se describen las prácticas recomendadas generales para diseñar clústeres de GKE escalables. Puedes aplicar estas recomendaciones en todos los clústeres y cargas de trabajo para lograr un rendimiento óptimo. Estas recomendaciones son especialmente importantes para los clústeres que planeas escalar en gran medida. Las prácticas recomendadas están destinadas a los administradores responsables de aprovisionar la infraestructura y a los desarrolladores que preparan los componentes de Kubernetes y las cargas de trabajo.

¿Qué es la escalabilidad?

En un clúster de Kubernetes, la escalabilidad se refiere a la capacidad del clúster para crecer dentro de los objetivos de nivel de servicio (SLO). Kubernetes también tiene su propio conjunto de SLO.

Kubernetes es un sistema complejo, y su capacidad de escalar está determinada por varios factores. Algunos de estos factores incluyen el tipo y la cantidad de nodos en un grupo de nodos, los tipos y la cantidad de grupos de nodos, la cantidad de pods disponibles, cómo se asignan los recursos a los pods y la cantidad de servicios o backends detrás de un servicio.

Prácticas recomendadas para la disponibilidad

Elige un plano de control regional o zonal

Debido a las diferencias en la arquitectura, los clústeres regionales son más adecuados para una alta disponibilidad. Los clústeres regionales tienen varios planos de control en múltiples zonas de procesamiento en una región, mientras que los clústeres zonales tienen un plano de control en una sola zona de procesamiento.

Si se actualiza un clúster zonal, la VM del plano de control experimenta un tiempo de inactividad durante el cual la API de Kubernetes no está disponible hasta que se completa la actualización.

En los clústeres regionales, el plano de control permanece disponible durante el mantenimiento de los clústeres, como la rotación de las IP, la actualización de las VM del plano de control o el cambio de tamaño de clústeres o grupos de nodos. Cuando se actualiza un clúster regional, dos de cada tres VM del plano de control siempre están en ejecución durante la actualización progresiva, por lo que la API de Kubernetes aún está disponible. Del mismo modo, una interrupción de una sola zona no causará ningún tiempo de inactividad en el plano de control regional.

Sin embargo, los clústeres regionales con alta disponibilidad tienen ciertas compensaciones:

  • Los cambios en la configuración del clúster demoran más tiempo porque deben propagarse en todos los planos de control en un clúster regional, en lugar del plano de control único en los clústeres zonales.

  • Es posible que no puedas crear ni actualizar clústeres regionales con tanta frecuencia como los clústeres zonales. Si no se pueden crear VMs en una de las zonas, ya sea por falta de capacidad o cualquier otro problema transitorio, no se podrán crear ni actualizar los clústeres.

Debido a estas compensaciones, los clústeres zonales y regionales tienen casos prácticos diferentes:

  • Usa clústeres zonales para crear o actualizar clústeres con rapidez cuando la disponibilidad no sea una preocupación.
  • Usa clústeres regionales cuando la disponibilidad sea más importante que la flexibilidad.

Selecciona con cuidado el tipo de clúster cuando crees uno porque no puedes cambiarlo después. En su lugar, debes crear un clúster nuevo y, luego, migrar el tráfico hacia él. La migración del tráfico de producción entre clústeres es posible, pero difícil hacerlo a gran escala.

Elige grupos de nodos multizonales o de zona única

Para lograr una alta disponibilidad, el plano de control de Kubernetes y sus nodos deben distribuirse en diferentes zonas. GKE ofrece dos tipos de grupos de nodos: de zona única y multizonales.

Para implementar una aplicación con alta disponibilidad, distribuye la carga de trabajo entre varias zonas de procesamiento de una región mediante grupos de nodos multizonales que distribuyen los nodos de manera uniforme entre distintas zonas.

Si todos los nodos están en la misma zona, no podrás programar Pods si no se puede acceder a la zona. El uso de grupos de nodos multizonales tiene ciertas compensaciones:

  • Las GPU solo están disponibles en zonas específicas. Puede que no sea posible obtenerlos en todas las zonas de la región.

  • La latencia de ida y vuelta entre zonas dentro de una sola región puede ser mayor que la de los recursos de una sola zona. La diferencia debe ser inmaterial para la mayoría de las cargas de trabajo.

  • El precio del tráfico de salida entre zonas de la misma región está disponible en la página de precios de Compute Engine.

Prácticas recomendadas para el escalamiento

Infraestructura base

Las cargas de trabajo de Kubernetes requieren redes, procesamiento y almacenamiento. Debes proporcionar suficiente memoria y CPU para ejecutar pods. Sin embargo, existen más parámetros de infraestructura subyacente que pueden influir en el rendimiento y la escalabilidad de un clúster de GKE.

Redes de clústeres

El uso de un clúster nativo de la VPC es la opción predeterminada de las herramientas de redes y la opción recomendada para configurar clústeres de GKE nuevos. Los clústeres nativos de la VPC permiten cargas de trabajo más grandes, una mayor cantidad de nodos y algunas otras ventajas.

En este modo, la red de VPC tiene un rango secundario para todas las direcciones IP de los Pods. A cada nodo se le asigna una porción del rango secundario para sus propias direcciones IP de Pods. Esto permite que la red de VPC entienda de forma nativa cómo enrutar el tráfico a los Pods sin depender de rutas personalizadas. Una sola red de VPC puede tener hasta 15,000 VMs.

Otro enfoque, que está obsoleto y que no admite más de 1,500 nodos, es usar un clúster basado en rutas. Un clúster basado en rutas no es una buena opción para cargas de trabajo grandes, ya que consume la cuota de las rutas de VPC y carece de otros beneficios de las herramientas de red nativas de la VPC. Para que funcione, agrega una ruta personalizada nueva a la tabla de enrutamiento en la red de VPC de cada nodo nuevo.

Clústeres privados

En los clústeres de GKE normales, todos los nodos tienen direcciones IP públicas. En los clústeres privados, los nodos solo tienen direcciones IP internas para aislar los nodos desde la conectividad entrante y saliente hacia Internet. GKE usa el intercambio de tráfico de redes de VPC para conectar las VMs que ejecutan el servidor de la API de Kubernetes con el resto del clúster. Esto permite una mayor capacidad de procesamiento entre los planos de control y los nodos de GKE, ya que el tráfico se enruta mediante direcciones IP privadas.

Usar clústeres privados tiene el beneficio de seguridad adicional de que los nodos no están expuestos a Internet.

Balanceo de cargas del clúster

Ingress de GKE y Cloud Load Balancing configuran e implementan balanceadores de cargas para exponer las cargas de trabajo de Kubernetes fuera del clúster y, también, a la Internet pública. Los controladores de Ingress y Service de GKE implementan objetos como reglas de reenvío, mapas de URL, servicios de backend, grupos de extremos de red, entre otros, en nombre de las cargas de trabajo de GKE. Cada uno de estos recursos tiene cuotas y límites inherentes, que también se aplican en GKE. Cuando un recurso de Cloud Load Balancing en particular alcance su cuota, evitará que un objeto Ingress o Service determinado se implemente de manera correcta y aparecerán errores en los eventos del recurso.

En la siguiente tabla, se describen los límites de escalamiento cuando se usan objetos Ingress y Service de GKE:

Balanceador de cargas Límite de nodos por clúster
Balanceador de cargas de red de transferencia interno
Balanceador de cargas de red de transferencia externo 1000 nodos por zona
Balanceador de cargas de aplicaciones externo
Balanceador de cargas de aplicaciones interno Sin límite de nodos

Si necesitas escalarla aún más, comunícate con el equipo de ventas de Google Cloud para aumentar este límite.

DNS

El descubrimiento de servicios en GKE se proporciona a través de kube-dns, que es un recurso centralizado para proporcionar una resolución de DNS a los Pods que se ejecutan dentro del clúster. Esto puede generar un cuello de botella en clústeres muy grandes o para cargas de trabajo que tienen una carga de solicitudes alta. GKE realiza un ajuste de escala automático de kube-dns según el tamaño del clúster para aumentar su capacidad. Cuando esta capacidad aún no es suficiente, GKE ofrece una resolución local distribuida de las consultas de DNS en cada nodo con NodeLocal DNSCache. Esto proporciona una caché de DNS local en cada nodo de GKE que responde a las consultas de manera local, distribuye la carga y proporciona tiempos de respuesta más rápidos.

Administra direcciones IP en clústeres nativos de la VPC

Un clúster nativo de la VPC usa tres rangos de direcciones IP:

  • Rango principal para la subred de nodos: La configuración predeterminada es /20 (4,092 direcciones IP).
  • Rango secundario para la subred de Pods: La configuración predeterminada es /14 (262,144 direcciones IP). Sin embargo, puedes configurar la subred de Pods.
  • Rango secundario para la subred de Service: La configuración predeterminada es /20 (4,096 direcciones). Sin embargo, no puedes cambiar este rango después de crear esta subred de Service.

Si deseas obtener más información, consulta Rangos de direcciones IP para clústeres nativos de la VPC.

Limitaciones y recomendaciones de direcciones IP:

  • Límite de nodos: El límite de nodos se determina según la dirección IP principal y la de Pod por nodo. Debe haber suficientes direcciones en los rangos de direcciones IP de nodo y de Pod para aprovisionar un nodo nuevo. De forma predeterminada, puedes crear solo 1,024 nodos debido a las limitaciones de direcciones IP de Pod.
  • Límite de Pods por nodo: De forma predeterminada, el límite de Pods por nodo es de 110 Pods. Sin embargo, puedes configurar CIDR de Pods más pequeños para un uso eficiente con menos Pods por nodo.
  • Escalamiento más allá de RFC 1918: Si necesitas más direcciones IP que las disponibles en el espacio privado definido por RFC 1918, te recomendamos que uses direcciones privadas que no sean de RFC 1918 o PUPI para obtener flexibilidad adicional.
  • Rango de direcciones IP secundario para Service y Pod: De forma predeterminada, puedes configurar 4,096 Services. Sin embargo, puedes configurar más Services si eliges el rango de subred de Service. No puedes modificar los rangos secundarios después de su creación. Cuando crees un clúster, asegúrate de elegir rangos lo suficientemente grandes para adaptarse al crecimiento previsto. Sin embargo, puedes agregar más direcciones IP para los Pods más adelante con CIDR de varios Pods no contiguos. Si deseas obtener más información, consulta No hay suficiente espacio de direcciones IP gratuito para Pods.

Para obtener más información, consulta Rangos de límite de nodos y Planifica las direcciones IP cuando migres a GKE.

Configura nodos para un mejor rendimiento

Los nodos de GKE son máquinas virtuales de Google Cloud normales. Algunos de sus parámetros, por ejemplo, la cantidad de núcleos o el tamaño del disco, pueden influir en el rendimiento de los clústeres de GKE.

Reduce los tiempos de inicialización del Pod

Puedes usar la transmisión de imágenes para transmitir datos desde imágenes de contenedor aptas a medida que las cargas de trabajo las solicitan, lo que da como resultado tiempos de inicialización más rápidos.

Tráfico de salida

En Google Cloud, el tipo de máquina y la cantidad de núcleos asignados a la instancia determinan la capacidad de red. El ancho de banda de salida máximo varía de 1 a 32 Gbps, mientras que el ancho de banda de salida máximo para las máquinas e2-medium-2 predeterminadas es de 2 Gbps. Para obtener más información sobre los límites de ancho de banda, consulta Tipos de máquinas de núcleo compartido.

IOPS y capacidad de procesamiento del disco

En Google Cloud, el tamaño de los discos persistentes determina las IOPS y el rendimiento del disco. Por lo general, GKE usa discos persistentes como discos de arranque y para respaldar los volúmenes persistentes de Kubernetes. El aumento del tamaño del disco incrementa tanto IOPS como el rendimiento, hasta ciertos límites.

Cada operación de escritura de disco persistente contribuye al límite de salida de red acumulativo de la instancia de máquina virtual. Por lo tanto, el rendimiento de IOPS de los discos, en especial los SSD, también depende de la cantidad de CPU virtuales en la instancia, además del tamaño del disco. Las VMs de núcleo inferior tienen límites de IOPS de escritura más bajos debido a las limitaciones de salida de red en la capacidad de procesamiento de escritura.

Si tu instancia de máquina virtual no tiene suficientes CPU, tu aplicación no podrá acercarse al límite de IOPS. Como regla general, debes tener una CPU disponible para cada 2,000 o 2,500 IOPS de tráfico esperado.

Para las cargas de trabajo que requieren una alta capacidad o una gran cantidad de discos, se debe tener en cuenta los límites de la cantidad de PD que se pueden conectar a una sola VM. Para las VM normales, ese límite es de 128 discos con un tamaño total de 64 TB, mientras que las VMs con núcleo compartido tienen un límite de 16 PD con un tamaño total de 3 TB. Google Cloud aplica este límite, no Kubernetes.

Supervisa las métricas del plano de control

Usa las métricas del plano de control disponibles para configurar tus paneles de supervisión. Puedes usar métricas de plano de control para observar el estado del clúster o los resultados de los cambios de configuración del clúster (por ejemplo, implementar cargas de trabajo adicionales o componentes de terceros), o cuando solucionas problemas.

Una de las métricas más importantes que se deben supervisar es la latencia de la API de Kubernetes. Cuando la latencia aumenta, esto indica que se sobrecarga el sistema. Ten en cuenta que las llamadas LIST que transfieren grandes cantidades de datos tienen una latencia mucho más alta que las solicitudes más pequeñas.

Una mayor latencia de la API de Kubernetes también puede deberse a una respuesta lenta de los webhooks de admisión de terceros. Puedes usar métricas para medir la latencia de los webhooks a fin de detectar estos problemas habituales.

Prácticas recomendadas para desarrolladores de Kubernetes

Usa la lista y el patrón de observación en lugar de la lista periódica

Como desarrollador de Kubernetes, es posible que debas crear un componente que tenga los siguientes requisitos:

  • Tu componente debe recuperar la lista de algunos objetos de Kubernetes de forma periódica.
  • Tu componente debe ejecutarse en varias instancias (en caso de DaemonSet, incluso en cada nodo).

Este componente puede generar aumentos repentinos de carga en el kube-apiserver, incluso si el estado de los objetos recuperados de forma periódica no cambia.

El enfoque más simple es usar llamadas LIST periódicas. Sin embargo, este es un enfoque ineficiente y costoso para el emisor y el servidor porque todos los objetos se deben cargar en la memoria, serializar y transferir cada vez. El uso excesivo de solicitudes LIST puede sobrecargar el plano de control o generar una limitación pesada de esas solicitudes.

Para mejorar tu componente, configura el parámetro resourceresource=0 en las llamadas LIST. Esto permite que kube-apiserver use la caché de objetos en la memoria y reduce la cantidad de interacciones internas entre kube-apiserver y la base de datos etcd y el procesamiento relacionado.

Te recomendamos evitar las llamadas LIST repetibles y reemplazarlas por la lista y el patrón de observación. Enumera los objetos una vez y, luego, usa la API de Watch para obtener cambios incrementales del estado. Este enfoque reduce el tiempo de procesamiento y minimiza el tráfico en comparación con las llamadas LIST periódicas. Cuando los objetos no cambian, no se genera ninguna carga adicional.

Si usas el lenguaje Go, marca SharedInformer y SharedInformerFactory para los paquetes de Go que implementan este patrón.

Limita el tráfico innecesario generado por las observaciones y las listas

Kubernetes usa watches para enviar notificaciones sobre actualizaciones de objetos. Incluso con observaciones que requieren muchos menos recursos que las llamadas LIST periódicas, el procesamiento de observaciones en clústeres grandes puede tomar una parte significativa de los recursos del clúster y afectar su rendimiento. El mayor impacto negativo se genera mediante la creación de observaciones que señalan objetos que cambian con frecuencia de varios lugares. Por ejemplo, mediante la observación de los datos sobre todos los Pods de un componente que se ejecuta en todos los nodos. Si instalas código o extensiones de terceros en tu clúster, pueden crear estas observaciones de forma interna.

Estas son las prácticas recomendadas:

  • Reduce el procesamiento y el tráfico innecesarios que generan los watches y las llamadas a LIST.
  • Evita crear watches que observen objetos que cambian con frecuencia de varios lugares (por ejemplo, DaemonSets).
  • Crea un controlador central que supervise y procese los datos necesarios en un solo nodo (altamente recomendado).
  • Observa solo un subconjunto de los objetos, por ejemplo, kubelet en cada nodo solo observa los Pods programados en el mismo nodo.
  • Evita implementar componentes o extensiones de terceros que podrían afectar el rendimiento del clúster mediante un gran volumen de watches o llamadas LIST.

Limita el tamaño del manifiesto de objetos de Kubernetes

Si necesitas operaciones rápidas que requieren una alta capacidad de procesamiento de Pods, como cambiar el tamaño o actualizar cargas de trabajo grandes, asegúrate de mantener al mínimo los tamaños de manifiesto del Pod, idealmente por debajo de 10 KiB.

Kubernetes almacena manifiestos de recursos en etcd. El manifiesto completo se envía cada vez que se recupera el recurso, incluso cuando usas la lista y el patrón de vigilancia.

El tamaño del manifiesto tiene las siguientes limitaciones:

  • Tamaño máximo de cada objeto en etcd: Alrededor de 1.5 MiB.
  • Cuota total para todos los objetos etcd en el clúster:El tamaño de cuota preconfigurado es de 6 GiB. Esto incluye un registro de cambios con todas las actualizaciones de todos los objetos en los 150 segundos más recientes del historial del clúster.
  • Rendimiento del plano de control durante períodos de tráfico alto: Los tamaños de manifiesto más grandes aumentan la carga en el servidor de la API.

En el caso de los objetos procesados de forma única y con muy poca frecuencia, el tamaño del manifiesto no suele ser un problema, siempre y cuando sea inferior a 1.5 MiB. Sin embargo, los tamaños de manifiesto superiores a 10 KiB para varios objetos procesados con frecuencia, como los pods en cargas de trabajo muy grandes, pueden causar una mayor latencia de llamada a la API y una disminución del rendimiento general. En particular, las listas y los objetos de supervisión pueden verse afectados de forma significativa por los tamaños de manifiestos grandes. Es posible que también tengas problemas con la cuota de etcd, ya que la cantidad de revisiones en los últimos 150 segundos puede acumularse rápidamente durante períodos de tráfico alto del servidor de API.

A fin de reducir el tamaño del manifiesto de un Pod, Kubernetes ConfigMaps puede aprovecharse para almacenar parte de la configuración, especialmente la parte que comparten varios pods en el clúster. Por ejemplo, a menudo, todos los Pods de una carga de trabajo comparten las variables de entorno.

Ten en cuenta que también es posible tener problemas similares con los objetos ConfigMap si estos son numerosos, grandes y procesados como los Pods. Extraer parte de la configuración es más útil cuando disminuye el tráfico general.

Inhabilita la activación automática de la cuenta de servicio predeterminada

Si la lógica que se ejecuta en tus Pods no necesita acceder a la API de Kubernetes, debes inhabilitar la activación automática y predeterminada de la cuenta de servicio para evitar la creación de Secrets y watches relacionados.

Cuando creas un Pod sin especificar una cuenta de servicio, Kubernetes realiza las siguientes acciones de manera automática:

  • Asigna la cuenta de servicio predeterminada al Pod.
  • Activa las credenciales de la cuenta de servicio como un Secret para el pod.
  • Por cada Secret activado, el kubelet crea un reloj para observar los cambios en ese Secret en cada nodo.

En clústeres grandes, estas acciones representan miles de observaciones innecesarias que pueden poner una carga significativa en el kube-apiserver.

Usa búferes de protocolo en lugar de JSON para solicitudes a la API

Usa búferes de protocolo cuando implementes componentes altamente escalables, como se describe en Conceptos de la API de Kubernetes.

La API de REST de Kubernetes admite JSON y búferes de protocolo como un formato de serialización para los objetos. JSON se usa de forma predeterminada, pero los búferes de protocolo son más eficientes para lograr un gran rendimiento a gran escala porque requieren menos procesamiento intensivo de CPU y envían menos datos a través de la red. La sobrecarga relacionada con el procesamiento de JSON puede causar tiempos de espera cuando se enumeran datos de gran tamaño.

Próximos pasos