Arquitectura Serverless con Lambdas sobre AWS

Índice de contenidos

1. Introducción

¿Estás ya cansado de los microservicios? Da el siguiente paso con una arquitectura serverless. Serverless es una forma de construir aplicaciones en la que nos centramos en el código, abstrayendonos aún más de los sistemas, máquinas, disponibilidad, escalado, etc.

Para ello haremos uso de “lambdas”. Vamos a explicar en qué consiste esto y verás como ahora el “micro” de microservicio si tendrá sentido. Implementaremos un ejemplo sencillito de API y lo pondremos en producción. Utilizaremos un framework llamado “Serverless” que nos facilitará el despliegue, y tendremos en un momento nuestra API desplegada sobre la plataforma cloud de Amazon.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2,2 GHz Intel Core i7, 16GB DDR3).
  • Sistema Operativo: Mac OS High Sierra
  • Entorno de desarrollo: Visual Studio Code
  • Software: serverless framwork, aws client, nodejs

3. Lambdas

Las “lambdas” o “functions” son pequeñas unidades funcionales de código que se ejecutarán bajo los eventos que se configuren: llamadas a un endpoint, eventos en una cola, cada cierto tiempo, cuando se crea/elimina un fichero de un directorio…

Cada proveedor de cloud ofrece su solución. Todas son parecidas, suelen cobrar por tiempo de ejecución y RAM consumida. No por ciclos de reloj, si no por el tiempo entre el inicio y fin de ejecución de la función aunque esté ociosa. Los proveedores más famosos son:

4. Serverless framework

El framework Serverless es una herramienta para facilitar el despliegue de nuestro código y la configuración de eventos, bases de datos y de más piezas de la arquitectura.

Soporta varios proveedores de cloud y hace que poner en funcionamiento nuestro código sea realmente sencillo y la configuración quede muy organizada y centralizada en el propio código de nuestro programa.

Más información en: https://serverless.com/framework/

5. Ejemplo

Para demostrar el funcionamiento vamos a implementar un CRUD con un simple API REST que permita crear, actualizar, leer y borrar libros de una base de datos.

De todos los lenguajes de programación que podríamos elegir para implementarlo hemos elegido JavaScript por su sencillez y para intentar que cualquiera pueda seguir el tutorial. Pero se podría implementar para AWS Lambdas en los siguientes lenguajes: Node.js (JavaScript), Python, Java (compatible con Java 8), C# (.NET Core) y Go.

Crearemos un servicio con las siguientes funciones:

  • createBook – para crear un registro
  • updateBook – para actualizar un registro concreto
  • getBooks – para obtener todos los registros
  • getBook – para obtener un registro concreto
  • deleteBooks – para borrar un registro concreto

Puedes ver el código completo en este repositorio de GitHub: https://github.com/miyoda/serverless-example

Configuración de Serverless

Dentro de nuestro proyecto creamos un directorio “books” que es un proyecto NodeJS independiente que será nuestro servicio “books” con las 5 funciones arriba indicadas.

Con un fichero “serverless.yml” definimos toda la configuración de la arquitectura y despliegue de nuestro servicio.

En el inicio del fichero marcamos el nombre del servicio el cual concatenará al nombre de todas las lambdas junto con el nombre de entorno/stage.

En el apartado “provider” marcamos donde se desplegará, para qué entorno, en qué región y lenguaje de programación. También podemos configurar variables de entorno como el nombre de la base de datos que puede depender de variables más globales como el nombre del servicio y el entorno.

En el apartado “functions” definimos nuestras “lambdas” indicando qué manejador contiene el código y bajo qué eventos se lanza. Hemos configurado eventos http con los verbos y rutas típicas de una API REST.

Y por último definimos la base de datos. En este caso un DynamoDB que es la base de datos NoSQL de AWS

Código NodeJS

Primero configuramos en el fichero ‘dynamodb.js’. Este incluirá la configuración para la conexión a la base de datos dependiendo de si ejecutamos en local o en cloud.

En el fichero ‘handler.js’ creamos las diferentes funciones. Por ejemplo la función de creación de la entidad “book” sería:

La función recibe tres parámetros: event, context y callback.

El parámetro ‘event’ contiene toda la información del evento que lanzo la petición. Por ejemplo en caso de ser un evento de un endpoint llevará los parámetros y los headers del request.

El parámetro ‘context’ contiene información sobre el entorno de ejecución actual de la función. Puedes encontrar más información de este parámetro aquí.

Y por último el parámetro ‘callback’ es la función que debemos llamar para retornar el resultado de la función. Su primer parámetro es el error (si lo hay) y el segundo un string con el resultado (ignorado si el error no era null). Para una respuesta JSON hay que parsearla con “JSON.stringify(…)”. Más información aquí

Podéis ver el resto del fichero ‘handler.js’ aquí; pues no es el objetivo del tutorial aprender NodeJS

6. Despliegue

Vamos a proceder a desplegar nuestras funciones en local y en AWS. Para ello primero tenemos que tener instalado “serverless”:

Instalamos también las dependencias declaradas en el fichero “books/package.json” con:

Despliegue en local

Para poder desplegar en local primero debemos instalar dynamoDB en local para poder conectar a la base de datos. Para ello ejecutamos dentro del directorio “books” el comando siguiente:

Y ahora procedemos a arrancar todo en local con el siguiente comando:

En el fichero “curls.sh” tenéis ejemplos de peticiones a nuestra API REST en el que se lanzan peticiones “curl” a los endpoints de las 5 funciones.

Despliegue en AWS

Vamos a proceder a desplegar en AWS nuestras funciones. Tenemos que tener instalado y configurado el cliente de AWS. Si no tienes una cuenta puedes crearla y usar la capa gratuita de AWS que ofrece más que de sobra para todas las pruebas que queráis. Podéis ver cómo instalar el cliente aquí y como configurarlo aquí.

Serverless basándose en la configuración que hemos definido en el fichero “books/serverless.yml” nos creará todas las piezas necesarias dentro del ecosistema de AWS con solo ejecutar:

Esto nos mostrará una salida por consola donde veremos que componentes/piezas se están desplegando en AWS y nos mostrará el endpoint que ha creado para cada una de nuestras funciones para que podamos consultarlo. Podemos ver toda esta información reflejada en la consola de AWS.

En este caso se ha desplegado simplemente algo así:

La primera pieza es un “API Gateway”. Este se encarga de gestionar los endpoints de la API, los conecta con las funciones y ofrece monitorización, escalado, autorización y versionado.

Las siguientes piezas son las propias funciones que nos conectará a un sistema de recopilación de logs con “Amazon CloudWatch Logs” que podremos consultar con:

La última pieza es la base de datos NoSQL llamada DynamoDB que podremos administrar online desde la propia consola de AWS.

Podéis modificar el fichero “curls.sh” para que apunte a vuestra API en AWS y probarla. Pero ya debería estar operativa y totalmente preparada para escalar y aguantar una buena biblioteca!

Con el siguiente comando podemos borrar todos los elementos que serverless ha dado de alta en AWS automáticamente:

7. Conclusiones

Como veis con AWS Lambdas y el framework Serverless es muy sencillo y rápido crear una API totalmente operativa y altamente escalable en cuestión de un rato. Es ideal para crear pequeñas aplicaciones, pilotos, o incluso con un poco más de arquitectura aplicaciones complejas altamente eficientes.

En próximos tutoriales veremos cómo el framework Serverless también facilita la utilización de otras piezas de AWS como SNS para poder interconectar funciones entré si con bajo acoplamiento mediante eventos. Esto nos permitirá diseñar arquitecturas orientadas a eventos como CQRS. También podemos configurar sistemas de autorización personalizados para que se ejecuten automáticamente antes de invocar a nuestras funciones por ejemplo para validar y decodificar la información de un JWT.