Kubernetes es una herramienta de orquestación de contenedores muy útil para la implementación de microservicios y ampliamente utilizada por las empresas. Uno de los retos más importantes cuando trabajamos con microservicios, es la gestión de éstos; cómo escalarlos, cómo orquestarlos… como mantenerlos bajo control.
La manera en la que Kubernetes trabaja con los microservicios, es empaquetando cada componente del microservicio en diferentes contenedores y administrándolos a nivel de clúster. A grandes rasgos, Kubernetes nos puede ayudar con la implementación de microservicios en los siguientes ámbitos:
- Escalado automático: Kubernetes puede monitorear automáticamente el tráfico de red y la carga de trabajo de cada contenedor y escalar automáticamente el número de instancias para satisfacer la demanda. Esto permite que los microservicios se escalen de manera rápida y eficiente, sin tener que administrar manualmente el escalado.
- Balanceo de carga: Kubernetes también puede equilibrar automáticamente la carga de trabajo entre contenedores, lo que garantiza que cada instancia reciba una cantidad equitativa de tráfico. Esto mejora el rendimiento y la estabilidad de los microservicios, ya que las solicitudes no se acumulan en una instancia particular.
- Gestión de versiones: Kubernetes facilita la administración de versiones de microservicios; puede implementar varias versiones de un microservicio al mismo tiempo y enviar el tráfico a la versión adecuada según las reglas de enrutamiento. Esto permite prueba de nuevas características en una versión de prueba antes de implementarlas en la versión en producción (A/B testing).
- Resiliencia: Kubernetes puede garantizar que los microservicios estén siempre en funcionamiento. Si una instancia falla, Kubernetes puede reemplazarla automáticamente con una instancia nueva y saludable. Esto permite que los microservicios se recuperen rápidamente de fallos y mantengan la disponibilidad para los usuarios.
- Configuración dinámica: Kubernetes facilita la configuración dinámica de los microservicios. Puede actualizar la configuración de un microservicio sin tener que reiniciarlo. Esto permite una mayor flexibilidad y agilidad en la implementación de nuevos cambios y actualizaciones.
Durante la implementación de las soluciones usando contenedores en general y Kubernetes en particular, nos iremos encontrando problemas comunes que pueden solucionarse mediante soluciones comunes; mediante patrones. El uso de patrones es una práctica muy recomendable, ya que son una solución práctica que ya se ha desarrollado y comprobado en situaciones reales.
Existen múltiples patrones para cada tipo de problema, pero me gustaría poner el foco en los que se denominan patrones estructurales, que son aquellos que nos ayudan en la relación entre diferentes contenedores. Los patrones estructurales nos ayudarán a mantener los contenedores centrados en realizar una sola tarea. Dentro de esta categoría encontraríamos los patrones Init, Sidecar, Ambassador y Adapter.
Init (o Initializator)
Los contenedores Init en Kubernetes permiten separar las tareas relacionadas con la inicialización de la lógica de la aplicación principal. Esta separación garantiza que todos los pasos de inicialización se completen correctamente en la secuencia definida antes de iniciar los contenedores principales de la aplicación. Se pueden concatenar varios contenedores init para que la inicialización se realice secuencialmente, asignando a cada contenedor una tarea. La lógica de negocio sólo estará disponible cuando se hayan ejecutado todos los contenedores init.
El patrón consiste en agregar uno o varios contenedores adicionales a mismo pod que el contenedor principal. El contenedor adicional actúa preparando la ejecución de la funcionalidad central, realizando tareas de inicialización antes de que se inicie la aplicación principal. Funcionan de manera similar a los constructores de algunos lenguajes de programación, de modo que hasta que no se satisfacen los requisitos de inicialización , la funcionalidad no está disponible

Podemos imaginar que se tiene una aplicación que necesita configuraciones específicas antes de que se pueda usar. En lugar de configurar manualmente la aplicación cada vez que se inicia, se puede agregar un Init para preparar el entorno antes de que se pueda usar la aplicación principal. El Initializator puede realizar tareas como la configuración de variables de entorno, la creación de archivos de configuración y la configuración de permisos o incluso descargar código de repositorios.
Sidecar (o Sidekick)
El patrón Sidecar se utiliza para extender la funcionalidad de un contenedor sin modificar su código. El patrón consiste en agregar un contenedor adicional al mismo pod que el contenedor principal. El contenedor adicional actúa como un Sidecar, proporcionando funcionalidad adicional al contenedor principal, como registros, métricas, almacenamiento en caché o seguridad. Habitualmente un contenedor representa un límite natural para una unidad de funcionalidad que tiene su propio tiempo de ejecución, ciclo de lanzamiento, API y equipo propietario. Un buen contenedor, se comporta como un único proceso linux, resuelve un problema y lo hace bien, y se crea con la idea de reemplazabilidad y reutilización. Mediante el uso del patrón Sidecar, podemos preservar al contenedor principal centrado en la lógica de negocio y tener otros contenedores que extiendan su funcionalidad sin interferencias .

Podemos imaginar que tenemos una aplicación que necesita acceso a una base de datos. En lugar de agregar lógica adicional a la aplicación para manejar la conexión a la base de datos, podemos agregar un Sidecar que administre la conexión. El Sidecar actúa como un intermediario entre la aplicación y la base de datos, proporcionando una conexión segura y confiable.
Ambassador
El patrón Ambassador es un caso particular del patrón Sidecar. Este patrón en sí, no extiende la funcionalidad del contenedor principal, sino que proporciona una visión unificada del mundo exterior a su contenedor, ocultando la complejidad y proporcionando una interfaz unificada a los servicios fuera del pod.
A veces, un contenedor debe trabajar con otros servicios a los que no es fácil acceder; estas dificultades se deben a cambios en las direcciones dinámicas, configuraciones complejas, elementos de seguridad, etc.Casi seguro que esta complejidad no nos interese mezclarla con la funcionalidad básica de nuestro contenedor principal, así que podemos recurrir a este patrón para solventarlo.

Con este modelo, nuestro contenedor de aplicaciones puede centrarse en realizar su procesamiento y delegar la responsabilidad y las particularidades del consumo de servicios externos en otro contenedor que le actúe de proxy.
Adapter
Si el patrón Ambassador nos permitía ocultar la complejidad del exterior a nuestro pod, el Adapter nos permite ocultar la complejidad de nuestro pod al exterior.
En este caso el contenedor se utiliza para exponer servicios en un clúster de Kubernetes a servicios externos. El patrón consiste en agregar un contenedor adicional al mismo pod que el contenedor principal. El contenedor adicional actúa como un proxy inverso, así podemos aprovecharlo para enrutar el tráfico del servicio al servicio correcto en el clúster o para ofrecer una interfaz unificada al exterior de los diferentes containers, muy útil para monitorización y extracción de datos. El Adapter actúa como un intermediario entre el servicio externo y los servicios internos, ocultando la complejidad de estos (y aportando mayor seguridad).

Podemos imaginar que tenemos varios servicios en un clúster de Kubernetes y queremos exponerlos a agentes externos. En lugar de configurar manualmente cada servicio para exponerlo al mundo exterior, podemos agregar un Ambassador para administrar el enrutamiento del tráfico externo.
Hemos visto como el uso de patrones es una manera efectiva para problemas comunes en la implementación de aplicaciones en Kubernetes. Si bien pueden parecer complejos al principio, son herramientas poderosas que pueden ahorrar tiempo y esfuerzo tanto en la implementación como en la administración y mantenimiento de aplicaciones.