Hoe een NodeJS-app serverloos te maken

Ik hoop dat je net zoveel van Serverless houdt als ik, want dit is weer een ander bericht over dat onderwerp.

Als we het nu hebben over een eenvoudige REST API zonder server, is uw configuratie vrij duidelijk op AWS: Lambda + API Gateway.

Maar hoe zit het met andere (micro) services die uw backend mogelijk heeft? Weet je, het is niet het beste idee om al je applicatiecode in een enkele monolithische AWS Lambda-functie te stoppen.

De uitdaging

We willen toepassingsmodules eenvoudig implementeren als serverloze microservices, die ook met elkaar moeten communiceren. Bij voorkeur moet de communicatie tussen services worden gereguleerd door een soort ACL.

Poging 1. API-gateway

Dit is de eerste gedachte die ik had toen ik het probleem probeerde op te lossen: onthul gewoon alle microservices via API Gateway. Het probleem is ... De gemaakte API's zijn openbaar.

Waarom is dit een probleem? We willen bijvoorbeeld niet dat een factureringsservice wordt blootgesteld aan de hele wereld, zelfs als de toegang wordt beperkt met een soort autorisatie.

Welnu, u kunt de API privé maken, maar het beveiligingsbeleid is vrij beperkt:

U kunt API Gateway-bronbeleid gebruiken om uw API veilig te laten gebruiken door:
* gebruikers van een gespecificeerd AWS-account
* gespecificeerde bron-IP-adresbereiken of CIDR-blokken
* gespecificeerde virtual private clouds (VPC's) of VPC-eindpunten (in elk account)

Dit maakt het lastig om de communicatie tussen dergelijke services te regelen. De enige manier om dit hier te doen is door services in afzonderlijke VPC's te plaatsen, te veel werk.

Poging 2. Lambda

Waarom stoppen we niet elke microservice in een afzonderlijke AWS Lambda? Zal dit het probleem oplossen?

Ja, het is in feite een serverloze microservice en u kunt het IAM-beleid gebruiken om de toegangen tussen services af te stemmen, maar ... Het is niet "eenvoudig".

Ik weet dat dit tegenwoordig heel normaal is om een ​​kleine functie als uw implementatie-eenheid te hebben. En in het geval dat uw service meer dan 1 eindpunt / methode / functie heeft, wordt het als goed beschouwd om deze als meerdere Lambdas te implementeren.

Ik begrijp de voordelen ervan, maar je offert onderhoudsgemak en ontwikkeling op. Ik houd ook niet zo van een idee om een ​​dienst te laten inzetten als een aantal Lambda-functies. Stel je voor, verschillende afzonderlijke functies die te maken hebben met facturering? Het is geen begrensde context meer. Hoewel er gevallen zijn waarin dergelijke granulariteit nuttig kan zijn, maar het is een zeldzaam geval.

Poging 3. Dikke Lambda

Kunnen we eigenlijk een set eindpunten inzetten als een enkele Lambda (zonder API Gateway natuurlijk te gebruiken)?

Als we dit zouden kunnen doen, zouden we alle voordelen van de vorige optie krijgen, maar we zouden ook de granulariteit van onze implementatie-eenheden kunnen kiezen.

De manier waarop ik het wil is als volgt: elke inzetbare service moet een eenvoudig, gewoon oud JS-object met methoden zijn. Dit is vrij eenvoudig te bereiken door een paar regels lijmcode toe te voegen tussen uw object en AWS Lambda.

Hier is mijn implementatie ervan: aws-rpc. Deze nodejs-module onthult de functie lambdaHandler, waar u een object passeert, en het wordt automatisch blootgesteld aan iedereen die toegang heeft tot de Lambda:

import {lambdaHandler} uit 'aws-rpc';
import {TestServiceImpl} uit './TestServiceImpl';
// dit is uw implementatie-eenheid
// dit is wat u opgeeft als Lambda's handler-functie
export const handler = lambdaHandler (new TestServiceImpl ());

Nu kunt u 'handler' gewoon als AWS Lambda inzetten. Hier is hoe je de methoden aanroept:

import {TestService} uit './TestService';
const client = wacht op createClient  ("LambdaName", "test");
console.log (wacht client.test () af);

Let op: om methoden voor het clientstub-object te kunnen genereren, moet u alle methodenamen doorgeven aan createClient, zoals in het voorbeeld.

Dit is vereist omdat JS geen runtime-informatie heeft over TypeScript-interfaces. Ik zou het kunnen implementeren met behulp van abstracte klassen, maar ik vind het niet leuk ¯ \ _ (ツ) _ / ¯.

Bonus! Je kunt het allemaal lokaal uitvoeren!

Ik geloof dat het heel belangrijk is om je lokale ontwikkelomgeving zo comfortabel mogelijk te maken. Daarom heb ik ook een mogelijkheid toegevoegd om de service en client lokaal uit te voeren zonder iets te implementeren in AWS (zie functies runService en createClient). Zie de repository op GitHub voor voorbeelden.

Overzicht

Dit is heel gemakkelijk om te verdwalen in de services die cloudproviders bieden en uw infrastructuur te overmatig te engineeren.

Ik kies altijd de meest eenvoudige en expliciete oplossing die ik kan bedenken. Onthoud ook dat veel technieken en praktijken kunnen worden hergebruikt vanaf andere platforms (het idee van de dikke NodeJS Lambda is geïnspireerd door zogenaamde dikke potten uit de Java-wereld).

Als je dit onderwerp leuk vond, bekijk dan ook deze:

  • Je moet leren hoe je de beste serverloze architectuur kunt maken
  • Hoe maak je een gratis serverloze CI / CD-pijplijn: 3 eenvoudige voorbeelden
  • Hoe DynamoDB eenvoudig in verschillende regio's te repliceren
  • Multiregionale applicatie maken (en nul betalen)
  • Maak elke Java Web App serverloos

Opmerkingen, likes en shares worden zeer op prijs gesteld. Proost!