Los microservicios representan un estilo de arquitectura y un modo de programar software. Con los microservicios, las aplicaciones se dividen en sus componentes más pequeños, y son independientes entre sí.

A diferencia del enfoque tradicional y monolítico de las aplicaciones, en el que todo se compila en una sola pieza, los microservicios son independientes y funcionan en conjunto para llevar a cabo las mismas tareas. Cada uno de estos elementos o procesos es un microservicio. Este enfoque privilegia el nivel de detalle, la sencillez y la capacidad de compartir un proceso similar en varias aplicaciones. Es un componente fundamental de la optimización del desarrollo de aplicaciones hacia un modelo nativo de la nube.

Docker a su vez es un proyecto de código abierto que automatiza el despliegue de aplicaciones dentro de contenedores de software. Esto permite, entre otras cosas, la abstracción y la automatización de los despliegues. En resumen, Docker sirve para encapsular nuestro código dentro de contenedores que contienen únicamente las dependencias necesarias para que nuestra aplicación funcione.

 

Ejemplo microservicios

 

A continuación, vamos a crear una arquitectura de microservicios para un e-commerce ficticio donde tendremos dos contenedores diferentes que se comuniquen entre sí donde uno nos aportará el listado de productos y el otro nos lo mostrará en una página web.

De esta forma podemos tener de una forma independiente una base de datos y un backend que nos aporten toda la conexión y tratamiento de información necesarios para que nuestra tienda funcione correctamente y por separado tendremos el front de la misma que se conectará con todos los servicios diferentes ( Productos, Carrito, Suscripciones, Descuentos, etc.) y mostrará los resultados al usuario.

Para simplificar mucho el código y el ejemplo vamos a crear solamente un microservicio que devuelva un listado de productos en formato json, sin conectarse a una base de datos. Como nuestros servicios son independientes, podemos crear cada uno de ellos en un lenguaje de programación diferente. Para el ejemplo, crearemos una API que devuelva el listado de productos utilizando Python y una página web que muestre dicho listado utilizando PHP.

Posteriormente crearemos una imagen de Docker para construir un contenedor donde encapsular nuestra API utilizando Dockerfile y le pasaremos la misma a un archivo docker-compose.yml para ejecutar nuestros contenedores y especificar sus dependencias.

Para nuestro ejemplo, vamos a crear una estructura de carpetas de la siguiente forma:

microservicios/
–>docker-compose.yml
—–> website/
———>index.php
—–> product/
———>api.py
———>Dockerfile
———>requirements.txt

Como no es un tutorial de programación, no entraremos en detalle acerca de las sentencias ejecutadas y estas mismas son bastante optimizables, pero estamos ante un ejemplo sencillo para entender la arquitectura de microservicios y la formar de desplegarla utilizando Docker.

 

Nuestro archivo api.py tendrá el siguiente aspecto:

from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)

class Product(Resource):
    def get(self):
        return {
            'products': ['Kobe Bryant jersey',
                        'LeBron James jersey',
                        'Rajon Rondo jersey',
                        'Dwayne Wade jersey']
        }

api.add_resource(Product, '/')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)

Este archivo tiene una serie de dependencias, propias de Python, que vamos a declarar en un archivo titulado requirements.txt en el mismo directorio:

Flask==0.12
flask_restful==0.3.5

A continuación, vamos a crear la imagen a partir de nuestro código y sus dependencias. Para ello, necesitamos partir de una imagen ya existente con las dependencias necesarias para ejecutar Python. La manera de buscar imágenes es a través de DockerHub y en este caso, utilizaremos la imagen oficial de Python 3. Si navegamos en la URL anterior, veremos ejemplos de Dockerfile que nos pueden servir para crear una imagen y construir y ejecutar un contenedor a través de la misma.

Nuestro Dockerfile tendrá el siguiente aspecto:

FROM python:3

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "python", "./api.py" ]

 

A estas alturas, ya tenemos nuestra imagen lista para nuestro microservicio de productos. El siguiente paso es crear un index.php vacío dentro del directorio de /website. Antes de crear nuestra tienda online, vamos a declarar las dependencias de nuestros microservicios y a construir sus contenedores. Para ello, en el directorio raíz (/microservicios), vamos a crear el archivo docker-compose.yml:

version: "3.7"


services:
    product-service:
        build: ./product
        volumes:
            - ./product:/usr/src/app
        ports:
            - 5001:80

    website:
        image: php:apache
        volumes:
            - ./website:/var/www/html
        ports:
            - 5000:80
        depends_on:
            - product-service

 

En el código anterior podemos comprobar que para construir el servicio de «product-service» hemos utilizando el comando de «build» para construir a través de una imagen disponible en la carpeta /product dentro del directorio actual y para el caso del servicio «website» se ha utilizado la imagen oficial de php que ofrece Apache instalado. También podemos observar que se ha añadido la dependencia de modo que el segundo servicio depende del primero ya que recibe información del mismo.

 

Ahora vamos a proceder con la creación de nuestro sitio web. Dentro de la carpeta /website, crearemos el archivo index.php:

<html>
    <head>
        <title>My NBA Store</title>
    </head>

    <body>
        <h1>Welcome to my NBA store</h1>
        <br>
        <ul>
            <?php
                $json = file_get_contents("http://product-service");
                $obj = json_decode($json);

                $products = $obj->products;
                
                foreach ($products as $product) {
                    echo "<li>$product</li>";
                }
            ?>
        </ul>
    </body>

 

Como puedes observar en el código anterior, la URL de nuestra API de productos es el nombre del servicio que le hemos puesto en nuestro docker-compose. Esto es debido a la dependencia que hemos especificado en el mismo archivo. Ahora que tenemos todo nuestro proyecto listo, ya podemos construir nuestros contenedores y ejecutarlos para probar su funcionamiento.

Esto lo conseguiremos con tan solo ejecutar el comando:

$ docker-compose up

(Para ejecutar el comando anterior necesitas tener instalado Docker en tu dispositivo previamente. Una vez instalado, asegúrate de que este está corriendo.)

Obtendrás un resultado como el siguiente:

Ejecutar docker-compose en Terminal

Ahora al visitar la dirección: http://localhost:5001/ obtendrás el resultado de la API de Python, algo como lo siguiente:

Para visitar la página final visita: http://localhost:5000/

Puedes comprobar como nuestra página, ubicada en un contenedor de Docker es capaz de hacer peticiones a nuestra API, ubicada en otro contenedor de Docker y escrita en un lenguaje de programación diferente.

 

Este sencillo ejemplo muestra las ventajas de utilizar Docker y una arquitectura de microservicios, permitiendo minimizar al máximo el mantenimiento de tu aplicación, reducir costes de servidores, mejorar tiempos, reducir recursos y costes, aislar dependencias, etc.