Para el servicio de copias de seguridad Clumio Protect, utilizamos Amazon Elastic Kubernetes Service (EKS) para gestionar nuestros clústeres de Kubernetes. La principal ventaja de utilizar un Kubernetes gestionado es que se consigue una estrecha integración con otros servicios de tu proveedor de nube. En concreto, cuando creas un nuevo servicio de Kubernetes, un controlador de servicios —proporcionado por AWS e instalado en el clúster— crea una nueva instancia de Elastic Load Balancer (ELB) y la configura para que redirija el tráfico hacia el servicio. Al mismo tiempo, ese controlador gestiona todo el ciclo de vida del equilibrador de carga correspondiente: proporciona una configuración correcta para sus comprobaciones de estado y mantiene actualizado el grupo de destino del equilibrador de carga cuando se añaden o eliminan nodos del clúster. Por último, elimina el equilibrador de carga cuando se elimina el servicio de Kubernetes del clúster.
Aunque resulta muy práctico utilizar los servicios de Kubernetes respaldados por los equilibradores de carga de AWS, hay varios aspectos que debemos tener en cuenta.
La arquitectura nativa de la nube de Clumio
Nuestra arquitectura se basa en microservicios, y cada uno de nuestros clústeres de Kubernetes cuenta con varias docenas de estos servicios. El número de servicios es especialmente notable en nuestros clústeres de desarrollo, donde alojamos tantos entornos de desarrollo aislados como podemos en un único clúster. En algunos clústeres de desarrollo, tenemos más de 300 servicios y la cifra sigue aumentando. Huelga decir que cada equilibrador de carga de AWS tiene un coste y no sería razonable que tuviéramos más de 300 equilibradores de carga de AWS solo para un único clúster de desarrollo. Otro problema es el límite de equilibradores de carga que puede admitir cada clúster de EKS. Este límite está relacionado con el número máximo de reglas en el grupo de seguridad de EC2. Concretamente, nuestro clúster de EKS medio no podría tener más de 60 equilibradores de carga clásicos. Para resolver este problema, decidimos utilizar Kubernetes Ingress para la mayoría de nuestros servicios. El mecanismo de Ingress nos permite compartir un único ELB entre varios servicios de un clúster de EKS, lo que reduce el consumo de recursos y los costes.
¿Por qué añadir Kubernetes Ingress?
La creación de un nuevo equilibrador de carga de AWS suele llevar cierto tiempo. Este retraso es aceptable para la mayoría de las operaciones; sin embargo, para determinados cambios —como, por ejemplo, el despliegue simultáneo de varios microservicios—, queríamos reducir al mínimo el tiempo necesario para que estuvieran en estado «Readiness». Para dar respuesta a este caso de uso, la incorporación de un nuevo Ingress de Kubernetes permite una puesta en marcha inmediata. Dependiendo de la implementación específica, un controlador de Ingress debe recargar la nueva configuración, al igual que los controladores de Ingress de Nginx, o bien aplicar la nueva configuración en tiempo de ejecución, al igual que los controladores de Ingress basados en Envoy.
Cuando se trabaja con servicios, se espera que cada uno de ellos tenga un nombre DNS, que puede ser externo. Con el enfoque de un ELB por servicio, no se puede crear un nombre DNS hasta que se haya creado el ELB. Con un único ELB preasignado para el controlador de Ingress, es posible asignar por adelantado tantos alias DNS como se desee a ese ELB, de modo que todos nuestros servicios estén disponibles tan pronto como creemos las definiciones de Ingress correspondientes.
Algunos de nuestros servicios exponen una API REST, pero la gran mayoría de ellos cuentan con puntos finales gRPC. Necesitábamos un controlador Ingress que admitiera tanto HTTPS como gRPC al mismo tiempo, y queríamos que el controlador Ingress se encargara de la terminación de TLS. Esto último no era un requisito estricto, y barajamos la posibilidad de utilizar sidecars de Istio para realizar la terminación de TLS directamente en un pod de microservicio. Sin embargo, decidimos utilizar el controlador de Ingress para realizar la terminación de TLS porque es más sencillo de gestionar y, en general, supone menos sobrecarga para el clúster. Otro requisito que teníamos era poder desplegar varias instancias del controlador de Ingress en el mismo clúster. Una definición específica de Ingress puede incluir una anotación kubernetes.io/ingress.class para especificar qué controlador de Ingress debe utilizarse.
Hemos probado varios controladores de Ingress y nos ha resultado sorprendentemente difícil encontrar uno que cumpliera todos los requisitos. Algunos controladores no funcionaban correctamente con gRPC, mientras que otros no admitían múltiples instancias de controlador en los mismos clústeres. Finalmente, descubrimos que el controlador de Ingress de NGINX se adapta a nuestras necesidades. Solo tuvimos que realizar un pequeño ajuste en su configuración para aumentar el tamaño del búfer de gRPC y que funcionara con nuestra pila de gRPC.
Mejoramos constantemente nuestros servicios a nivel de infraestructura para ampliarla y optimizar los costes de mantenimiento. Al principio, utilizábamos un equilibrador de carga dedicado por servicio, pero muy pronto alcanzamos el límite de equilibradores de carga por clúster. En ese momento, actualizamos nuestra infraestructura para utilizar controladores Ingress alojados para la conectividad externa de nuestros servicios y redujimos significativamente el número de equilibradores de carga clásicos de AWS necesarios para el producto. Utilizar el Application Load Balancer (ALB) de AWS no era una opción en aquel momento, ya que el ALB no era compatible con gRPC. A finales de 2020, AWS anunció que había añadido compatibilidad con HTTP/2 de extremo a extremo y gRPC para el Application Load Balancer. Ahora podemos utilizar el controlador AWS Load Balancer, anteriormente conocido como «AWS ALB Ingress Controller», que se cedió al Grupo de Interés Especial de Kubernetes de AWS (SIG-AWS) para permitir que AWS y otros colaboradores del SIG-AWS mantengan oficialmente el proyecto. Estamos deseando utilizar este controlador de Ingress en nuestra infraestructura. Otro de nuestros principales intereses es la API de Kubernetes Gateway, una nueva API de Kubernetes que se encuentra en fase de desarrollo a cargo del Grupo de Interés Especial en Redes (SIG-Network). En comparación con la API de Ingress, la API de Gateway ofrece una interfaz más general para el proxy que puede utilizarse con más protocolos además de HTTP, y modela más componentes de la infraestructura para proporcionar mejores opciones de implementación y gestión a los operadores de clústeres. Estamos deseando probar los futuros controladores de Kubernetes que implementen la API de Gateway.
Reducción del consumo de recursos y de los costes
El mecanismo Ingress de Kubernetes nos ayuda a reducir el consumo de recursos y los costes. Ya no estamos limitados por las restricciones de EC2 y EKS en cuanto al número de servicios desplegados en un único clúster gestionado de Kubernetes. Algunos de los controladores Ingress de código abierto funcionan con servicios gRPC de forma predeterminada, pero requieren una comprobación adicional para verificar si son adecuados para un caso de uso específico. La comunidad de Kubernetes proporciona y mejora constantemente las API de Kubernetes, como la API de Ingress o la API de Gateway, mientras que los proveedores comerciales y de código abierto ofrecen diversas implementaciones de dichas API. Esto permite elegir la implementación adecuada para un caso de uso concreto y sustituirlas sin necesidad de realizar cambios importantes a nivel de la aplicación.