Cómo hacer que cualquier aplicación NodeJS no tenga servidor

Espero que te guste Serverless tanto como a mí porque esta es otra publicación sobre ese tema.

Ahora, si estamos hablando de una API REST sin servidor simple, su configuración es bastante obvia en AWS: Lambda + API Gateway.

Pero, ¿qué hay de otros (micro) servicios que pueda tener su backend? Sabes, no es la mejor idea poner todo el código de tu aplicación en una sola función monolítica de AWS Lambda.

El reto

Queremos implementar fácilmente módulos de aplicación como microservicios sin servidor, que también necesitan comunicarse entre sí. Preferiblemente, la comunicación entre servicios debe estar regulada por algún tipo de ACL.

Intento 1. Puerta de enlace API

Este es el primer pensamiento que tuve cuando estaba tratando de resolver el problema: simplemente expongo todos los microservicios a través de API Gateway. El problema es ... Las API creadas son públicas.

¿Por qué es esto un problema? Por ejemplo, no queremos tener un servicio de facturación expuesto al mundo entero, incluso si el acceso está restringido mediante algún tipo de autorización.

Bueno, puedes hacer que la API sea privada, pero las políticas de seguridad son bastante limitadas:

Puede usar las políticas de recursos de API Gateway para permitir que su API sea invocada de forma segura por:
* usuarios de una cuenta de AWS especificada
* rangos de direcciones IP de origen especificados o bloques CIDR
* nubes privadas virtuales especificadas (VPC) o puntos finales VPC (en cualquier cuenta)

Esto hace bastante problemático controlar las comunicaciones entre dichos servicios. La única forma de hacerlo aquí es poniendo los servicios en VPC separadas, demasiado trabajo.

Intento 2. Lambda

¿Por qué no ponemos cada microservicio en un AWS Lambda separado? ¿Esto resolverá el problema?

Sí, de hecho, será un microservicio sin servidor, y podrá utilizar las políticas de IAM para ajustar los accesos entre servicios, pero ... No es "fácil".

Sé que esto es bastante normal hoy en día para tener una pequeña función como unidad de implementación. Y en el caso de que su servicio tenga más de 1 punto final / método / función, se considera correcto implementarlo como múltiples Lambdas.

Entiendo las ventajas, pero sacrificas la facilidad de mantenimiento y desarrollo. Además, realmente no me gusta la idea de tener un servicio implementado como un conjunto de funciones de Lambda. Imagínese, ¿varias funciones separadas relacionadas con la facturación? Ya no es un contexto acotado. Aunque hay casos en los que tal granularidad puede ser útil, es un caso raro.

Intento 3. Lambda gorda

¿Podemos implementar un conjunto de puntos finales como un único Lambda (sin usar API Gateway, por supuesto)?

Si pudiéramos hacer esto, obtendríamos todos los beneficios de la opción anterior, pero también podríamos elegir la granularidad de nuestras unidades de implementación.

La forma en que lo quiero es la siguiente: cada servicio desplegable debe ser un simple objeto JS simple con métodos. Esto es bastante trivial de lograr al agregar algunas líneas de código de pegamento entre su objeto y AWS Lambda.

Aquí está mi implementación: aws-rpc. Este módulo nodejs expone la función lambdaHandler, donde solo pasa un objeto, y se expone automáticamente a cualquiera que pueda acceder a Lambda:

importar {lambdaHandler} desde 'aws-rpc';
importar {TestServiceImpl} desde './TestServiceImpl';
// esta es tu unidad de despliegue
// esto es lo que especificas como la función de controlador de Lambda
exportar const handler = lambdaHandler (nuevo TestServiceImpl ());

Ahora, puede implementar "controlador" como AWS Lambda. Así es como invocas sus métodos:

importar {TestService} desde './TestService';
const client = await createClient  ("LambdaName", "test");
console.log (aguarde client.test ());

Tenga en cuenta que para poder generar métodos para el objeto de código auxiliar del cliente, debe pasar todos los nombres de métodos a createClient, como lo hicimos en el ejemplo.

Esto es necesario porque JS no tiene ninguna información de tiempo de ejecución sobre las interfaces TypeScript. Podría implementarlo usando clases abstractas, pero no me gusta ¯ \ _ (ツ) _ / ¯.

¡Prima! ¡Puedes ejecutarlo todo localmente!

Creo que es muy importante que su entorno de desarrollo local sea lo más cómodo posible. Es por eso que también he agregado la capacidad de ejecutar el servicio y el cliente localmente sin implementar nada en AWS (consulte las funciones runService y createClient). Para ver ejemplos, consulte el repositorio en GitHub.

Resumen

Es muy fácil perderse en los servicios que ofrecen los proveedores de la nube y diseñar en exceso su infraestructura.

Siempre elijo la solución más simple y explícita que se me ocurre. Además, recuerde siempre que muchas técnicas y prácticas pueden reutilizarse desde otras plataformas (la idea del gordo NodeJS Lambda está inspirada en los llamados tarros gordos del mundo Java).

Si te gustó este tema, mira estos también:

  • Tienes que aprender a hacer la mejor arquitectura sin servidor
  • Cómo crear un canal de CI / CD sin servidor gratuito: 3 ejemplos sencillos
  • Cómo replicar fácilmente DynamoDB en todas las regiones
  • Cómo hacer una aplicación multirregional (y Pay Zero)
  • Haga que cualquier aplicación web Java no tenga servidor

Comentarios, me gusta y acciones son muy apreciados. ¡Aclamaciones!