Este es el segundo instructivo de una ruta de aprendizaje que te enseña a modularizar y organizar en contenedores una app monolítica.
La ruta de aprendizaje consta de los siguientes instructivos:
- Descripción general
- Comprende la aplicación monolítica
- Modulariza la aplicación monolítica (este instructivo)
- Prepara la app modular para la organización en contenedores
- Crea contenedores para la app modular
- Implementa la app en un clúster de GKE
En el instructivo anterior, Comprende el monolito, aprendiste sobre una app monolítica llamada Cymbal Books. Ejecutaste el monolito en tu máquina local y aprendiste que las diferentes partes del monolito se comunican entre sí a través de sus extremos.
En este instructivo, verás cómo dividir el monolito en módulos para prepararlo para la contenerización. No es necesario que realices los pasos de modularización por tu cuenta, ya que el código ya se actualizó por ti. Tu trabajo es seguir el instructivo y explorar la versión modular de la app en el repositorio para ver en qué se diferencia del monolito original.
Costos
Puedes completar este instructivo sin incurrir en cargos. Sin embargo, seguir los pasos del instructivo final de esta serie genera cargos en tu cuenta deGoogle Cloud . Los costos comienzan cuando habilitas GKE y, luego, implementas la app de Cymbal Books en un clúster de GKE. Estos costos incluyen los cargos por clúster de GKE, como se describe en la página de precios, y los cargos por ejecutar VMs de Compute Engine.
Para evitar cargos innecesarios, asegúrate de inhabilitar GKE o borrar el proyecto una vez que hayas completado este instructivo.
Antes de comenzar
Antes de comenzar este instructivo, asegúrate de haber completado el primero, Comprende el monolito. En este instructivo, ejecutarás la versión modular de Cymbal Books en tu máquina local. Para ello, ya debes haber configurado tu entorno. Si ya completaste el primer instructivo, clonaste un repositorio de GitHub. Las tres versiones de la app de Cymbal Books se encuentran en ese repositorio, dentro de las siguientes carpetas:
monolith/
modular/
containerized/
Antes de continuar, verifica que estas carpetas estén en tu máquina. Además, asegúrate de que el entorno virtual book-review-env
esté activo. Si necesitas recordar cómo activarlo, consulta Crea y activa un entorno virtual en el primer instructivo. Activar el entorno garantiza que la versión modular de la app tenga todo lo que necesita para ejecutarse.
¿Qué es la modularización?
En este instructivo, aprenderás a modularizar la app monolítica para prepararla para la contenerización. La modularización es el proceso de convertir un monolito en una app modular. Como aprendiste en el instructivo anterior, la característica distintiva de un monolito es que sus componentes no pueden ejecutarse ni escalarse de forma independiente. Una app modular es diferente: su funcionalidad se divide en módulos que pueden ejecutarse y escalarse de forma independiente.
Si bien la modularización y la contenedorización suelen realizarse juntas, en esta serie de instructivos se tratan como pasos separados para ayudarte a comprender cada concepto con claridad. En este instructivo, se explica cómo modularizar un monolito, y en un instructivo posterior, se explica cómo alojar en contenedores la app modular.
Modularización incremental
En los entornos de producción, por lo general, se modulariza un componente a la vez. Modularizas el componente, integras el módulo con el monolito y te aseguras de que todo funcione antes de trabajar en el siguiente componente. Este estado híbrido, en el que algunos componentes se modularizan mientras que otros siguen formando parte del monolito, se denomina microlito. Sin embargo, en este instructivo, todos los componentes de la app se modularizan al mismo tiempo para proporcionar un ejemplo completo de cómo modularizar una app.
Cómo modularizar la aplicación monolítica
En esta sección, aprenderás cómo se dividió el monolito de Cymbal Books en módulos separados. Se proporcionan pasos para ayudarte a comprender el proceso de modularización, de modo que puedas aplicarlo a tus propias apps. Sin embargo, no es necesario que realices estos pasos en este instructivo porque el repositorio clonado ya incluye la versión modular de la app:
- Identifica las funciones distintas de la app
- Crea los módulos
- Habilita la comunicación entre los módulos
- Otorga a cada módulo acceso solo a los datos que necesita
Identifica las distintas funciones de la app
El primer paso para modularizar el monolito de Cymbal Books es identificar sus funciones principales. En la aplicación de muestra de Cymbal Books, el monolito tiene las siguientes cuatro funciones distintas:
- Entrega de la página principal
- Detalles de la publicación
- Publicación de opiniones sobre libros
- Entrega de imágenes de portadas de libros
Crea los módulos
Como viste en el instructivo anterior, el monolito es una sola app de Flask que implementa las cuatro funciones, que se identificaron en la sección anterior, como controladores de rutas. Para modularizar la app, toma cada controlador de ruta y colócalo en su propia app de Flask. En lugar de una app de Flask con cuatro controladores de ruta, tendrás cuatro apps de Flask, cada una con un solo controlador de ruta.
En el siguiente diagrama, se ilustra esta transformación de una sola app de Flask en cuatro apps de Flask separadas:
En la app modular, cada app de Flask se ejecuta de forma independiente y escucha en un puerto diferente (8080, 8081, 8082, 8083), como se muestra en el diagrama. Esta configuración es necesaria porque, cuando pruebes la app modular más adelante en este instructivo, ejecutarás todos los módulos en la misma máquina. Cada app necesita un número de puerto diferente para evitar conflictos.
El módulo de la página principal tiene dos responsabilidades: publica la página principal y se comunica con los otros módulos para recopilar los datos que se deben mostrar en una página web. Cada uno de los otros módulos se enfoca en una sola función: mostrar opiniones, detalles o imágenes. Estos módulos no se comunican entre sí, sino que solo responden a las solicitudes del módulo de la página principal.
Si bien el módulo de la página principal tiene un rol de coordinación adicional, la app sigue siendo verdaderamente modular porque puedes actualizar cualquier módulo sin afectar a los demás. La gran aplicación única de Flask se dividió en cuatro partes, cada una de las cuales controla una parte específica de la funcionalidad de la aplicación.
Habilita la comunicación entre los módulos
Después de crear los módulos, el siguiente paso es asegurarse de que puedan comunicarse entre sí. En la app de Cymbal Books, esta lógica de comunicación ya se implementó para ti. En la carpeta modular/
del código que descargaste, puedes ver que cada una de las funciones principales de la app (publicación de la página principal, detalles de libros, opiniones y imágenes) se implementa como una app de Flask independiente. Cada una de estas apps define su propio extremo HTTP, y los módulos se comunican enviando solicitudes HTTP a esos extremos.
La modularización del monolito de Cymbal Books fue sencilla. El monolito tiene componentes bien definidos que se implementan como controladores de rutas, y cada controlador de rutas tiene un extremo bien definido. Cuando estos controladores de rutas se colocan en aplicaciones de Flask separadas, conservan su capacidad de comunicarse a través de sus extremos. El simple acto de colocar los controladores de rutas en apps de Flask separadas crea los módulos y permite que se comuniquen entre sí.
Un enfoque común para la comunicación entre módulos es implementar APIs de REST, que permiten que los módulos se envíen solicitudes HTTP entre sí. Así es como funciona en Cymbal Books: cada módulo define extremos de REST con las herramientas integradas de Flask. Otro enfoque popular es gRPC, que permite que los módulos llamen directamente a las funciones de otros módulos.
Por qué la comunicación es sencilla en Cymbal Books
Cada módulo de la app modular es una aplicación de Flask independiente que se ejecuta dentro de un servidor web. Por ejemplo, el módulo de la página principal muestra la página principal, y el módulo de detalles del libro muestra los detalles del libro. La comunicación entre los módulos es sencilla porque los servidores web están diseñados para controlar las solicitudes y respuestas HTTP. Cada módulo expone extremos que otros módulos pueden usar para solicitar datos.
Otorga a cada módulo acceso solo a los datos que necesita
Para modularizar correctamente el monolito, debes asegurarte de que cada módulo tenga acceso solo a los datos que necesita. Este principio, conocido como aislamiento de datos, es un elemento fundamental para crear una arquitectura verdaderamente modular.
Un error frecuente que cometen las personas durante la modularización es permitir que varios módulos accedan a los mismos datos, como una sola base de datos. Este tipo de implementación genera problemas como los siguientes:
- Acoplamiento estrecho: Si cambia la estructura de los datos compartidos (por ejemplo, se cambia el nombre de una tabla de la base de datos o se agrega una columna), se debe actualizar cada módulo que dependa de esos datos. La modularización adecuada evita este problema.
- Problemas de tolerancia a fallas: Cuando varios módulos usan la misma fuente de datos, las fallas de tiempo de ejecución en un módulo (como consultas no válidas o tráfico abrumador) pueden interrumpir otros módulos. Una falla en una parte del sistema puede desencadenar fallas en otras partes.
- Cuellos de botella de rendimiento: Una sola fuente de datos compartida puede convertirse en un cuello de botella, lo que significa que podría ralentizar toda la aplicación cuando varios módulos intentan interactuar con ella.
Para evitar estos problemas, cada módulo debe tener su propia fuente de datos.
Si Cymbal Books hubiera usado una base de datos para almacenar sus datos, tendrías que replicar o particionar la base de datos para aplicar el aislamiento de datos y garantizar que cada módulo acceda solo a los datos que necesita. La replicación implica mantener copias separadas de la base de datos para cada módulo, mientras que la partición restringe el acceso a tablas o filas específicas. Ambos enfoques evitan que los módulos interfieran con los datos de otros módulos.
En el siguiente diagrama, se compara la arquitectura de la app de libros monolítica con la arquitectura modular de la app de libros:
La implementación del monolito no sigue el principio de aislamiento de datos, ya que las funciones del monolito acceden a un solo directorio data/
.
Por el contrario, la app modular logra cierto grado de aislamiento de datos dividiéndolos en directorios separados y garantizando que cada módulo interactúe solo con los datos designados:
- El módulo de detalles del libro solo obtiene datos del directorio
details_data/
. - El módulo de opiniones sobre libros solo obtiene datos del directorio
reviews_data/
. - El módulo de imágenes solo obtiene datos del directorio
images/
.
En un instructivo posterior, verás cómo el proceso de contenerización de la app puede mejorar aún más el aislamiento de los datos.
Lo que acabas de ver
En la industria del desarrollo de software, a menudo se encuentran los términos microservicios y sistemas distribuidos. En esta sección, se explica cómo se relacionan estos términos con la implementación modular de Cymbal Books.
Microservicios
Los microservicios son módulos autónomos que realizan tareas específicas. Estos módulos se comunican con otros módulos a través de interfaces, como los extremos.
Cada módulo de la versión modular de Cymbal Books se ajusta a esta definición y, por lo tanto, se puede considerar un microservicio. Cuando la app modular se containeriza en un instructivo posterior, el código que se ejecuta dentro de un contenedor también se puede denominar microservicio, ya que es el mismo código que se ejecuta dentro de un módulo.
Sistemas distribuidos
Un sistema distribuido consta de módulos independientes que se comunican a través de una red para lograr un objetivo común. Estos módulos pueden ejecutarse en diferentes máquinas, pero funcionan en conjunto como un solo sistema.
La app modular Cymbal Books también se ajusta a esta definición: sus módulos se ejecutan de forma independiente y se intercambian datos a través de HTTP, pero, en conjunto, funcionan como un solo sistema. En la siguiente sección, ejecutarás todos los módulos en una sola máquina para simplificar el proceso, pero no es obligatorio. Cada módulo podría ejecutarse con la misma facilidad en un servidor diferente, por lo que la versión modular de la app de Cymbal Books se puede clasificar como un sistema distribuido.
Prueba la implementación modular
Ahora que viste cómo se transforma el monolito de Cymbal Books en una app modular cuyos módulos son apps de Flask, puedes probar la aplicación y ver que cada módulo se ejecuta de forma independiente.
En este instructivo, ejecutarás los módulos en la misma máquina. Sin embargo, también podrías ejecutar cada módulo en un servidor independiente, ya que cada módulo es autónomo y puede comunicarse con los demás a través de sus extremos.
Configura tu entorno
Sigue estos pasos para prepararte para las pruebas:
En la terminal, navega al directorio
modular
en el repositorio clonado:cd modular
Asegúrate de que el entorno virtual
book-review-env
esté activo. Si necesitas un recordatorio sobre los pasos de activación, consulta Crea y activa un entorno virtual.
Inicia la app de Flask
La carpeta /modular
contiene una secuencia de comandos de Bash que inicia todas las aplicaciones de Flask de forma simultánea. Cada módulo de la app escucha en un puerto único, como 8080 o 8081:
- Página principal de la app de Flask (home.py): puerto 8080
- App de Flask de detalles del libro (book_details.py): puerto 8081
- App de Flask de opiniones sobre libros (book_reviews.py): puerto 8082
- App de Images Flask (images.py): puerto 8083
Cada módulo debe escuchar en un número de puerto único porque todos los módulos se ejecutan en la misma máquina. Si cada módulo estuviera en un servidor diferente, cada uno podría escuchar en el mismo número de puerto sin crear conflictos de puertos.
Ejecuta la secuencia de comandos Bash con este comando:
bash ./start_services.sh
La secuencia de comandos crea un archivo de registro independiente para cada app de Flask (por ejemplo, home.py.log
, book_details.py.log
) para ayudarte a identificar cualquier problema de inicio.
Cuando la secuencia de comandos se complete correctamente, verás este mensaje:
All services have been started. Access the app at http://localhost:8080/
Prueba cada app de Flask
Para probar los módulos, visita las siguientes URLs en tu navegador:
- Página principal:
http://localhost:8080/
muestra la página principal de la aplicación modularizada Cymbal Books. Esta página recupera detalles, imágenes y reseñas de libros haciendo solicitudes a los otros módulos. - Book details:
http://localhost:8081/book/1
devuelve los detalles del libro con el ID 1. Esta respuesta son datos JSON que la app luego formatea y muestra de una manera más legible. - Opiniones sobre libros:
http://localhost:8082/book/1/reviews
recupera y devuelve las opiniones sobre el libro con el ID 1. Las opiniones están en formato JSON. El módulo de la página principal solicita estos datos y los integra en la página de detalles del libro. - Imágenes:
http://localhost:8083/images/fungi_frontier.jpg
publica la imagen de la portada del libro Fungi Frontier. Si la URL es correcta, la imagen debería cargarse directamente en tu navegador.
Detén las apps de Flask
Cuando termines de realizar las pruebas, detén todas las apps de Flask con este comando:
kill $(cat home.py.pid book_details.py.pid book_reviews.py.pid images.py.pid)
Resumen
En este instructivo, se mostró cómo modularizar el monolito de Cymbal Books. El proceso consta de los siguientes pasos:
- Identifica los componentes distintos de la app
- Crea los módulos
- Garantizar que cada módulo solo tenga acceso a los datos que necesita
Luego, probaste la implementación modular en tu máquina local.
¿Qué sigue?
En el siguiente instructivo, Prepara la app modular para la contenedorización, aprenderás a preparar la app modular para la contenedorización actualizando los extremos para usar nombres de servicio de Kubernetes en lugar de localhost
.