Sådan gør du nogen NodeJS-appserver

Jeg håber, at du elsker Serverless så meget som jeg, fordi dette er endnu et indlæg om dette emne.

Hvis vi nu taler om et simpelt serverløst REST API, er din opsætning ganske åbenlyst på AWS: Lambda + API Gateway.

Men hvad med andre (mikro) tjenester, som din backend kan have? Du ved, det er ikke den bedste idé at placere al din applikationskode i en enkelt monolitisk AWS Lambda-funktion.

Udfordringen

Vi ønsker let at implementere applikationsmoduler som serverløse mikroservices, som også er nødt til at kommunikere med hinanden. Fortrinsvis skal kommunikationen mellem tjenester reguleres af en slags ACL.

Forsøg 1. API Gateway

Dette er den første tanke, som jeg havde, da jeg forsøgte at løse problemet: blot udsæt alle mikroservices via API Gateway. Problemet er ... De oprettede API'er er offentlige.

Hvorfor er dette et problem? For eksempel ønsker vi ikke at have en faktureringstjeneste, der skal udsættes for hele verden, selvom adgangen er begrænset ved hjælp af en form for tilladelse.

Du kan godt gøre API'en privat, men sikkerhedspolitikkerne er ret begrænsede:

Du kan bruge API Gateway-ressourcepolitikker til at tillade, at din API sikkert aktiveres af:
* brugere fra en specificeret AWS-konto
* specificerede kilde-IP-adresseintervaller eller CIDR-blokke
* specificerede virtuelle private skyer (VPC'er) eller VPC endpoints (i enhver konto)

Dette gør det ganske besværligt at kontrollere kommunikationen mellem sådanne tjenester. Den eneste måde at gøre det her på er ved at placere tjenester i separate VPC'er, for meget arbejde.

Forsøg 2. Lambda

Hvorfor lægger vi ikke bare hver mikroservice i en separat AWS Lambda? Vil dette løse problemet?

Ja, det vil faktisk være en serverløs mikroservice, og du vil kunne bruge IAM-politikker til at indstille adgangerne mellem tjenester, men ... Det er ikke “let”.

Jeg ved, at dette er helt normalt i dag at have en lille funktion som din implementeringsenhed. Og i det tilfælde, hvor din tjeneste har mere end 1 slutpunkt / metode / funktion, betragtes det som ok at implementere den som flere Lambdas.

Jeg forstår fordelene ved det, men du ofrer let vedligeholdelse og udvikling. Desuden kan jeg virkelig ikke lide en idé om at få en tjeneste implementeret som et sæt Lambda-funktioner. Forestil dig flere separate funktioner, der beskæftiger sig med fakturering? Det er ikke længere en afgrænset kontekst. Selvom der er tilfælde, hvor en sådan granularitet kan være nyttig, men det er et sjældent tilfælde.

Forsøg 3. Fat Lambda

Kan vi faktisk implementere et sæt slutpunkter som en enkelt Lambda (uden at bruge API Gateway, selvfølgelig)?

Hvis vi kunne gøre dette, ville vi få alle fordelene ved den foregående mulighed, men vi ville også være i stand til at vælge granulariteten i vores implementeringsenheder.

Den måde, jeg ønsker det på, er følgende: hver implementerbar tjeneste skal være et simpelt almindeligt gammelt JS-objekt med metoder. Dette er ganske trivielt at opnå ved at tilføje et par linjer limkode mellem dit objekt og AWS Lambda.

Her er min implementering af det: aws-rpc. Dette nodejs-modul afslører lambdaHandler-funktionen, hvor du bare passerer et objekt, og det udsættes automatisk for alle, der er i stand til at få adgang til Lambda:

import {lambdaHandler} fra 'aws-rpc';
import {TestServiceImpl} fra './TestServiceImpl';
// dette er din installationsenhed
// det er det, du angiver som Lambdas handlerfunktion
eksport const handler = lambdaHandler (ny TestServiceImpl ());

Nu kan du bare implementere “handler” som AWS Lambda. Sådan påpeger du dens metoder:

import {TestService} fra './TestService';
const client = vente på createClient  ("LambdaName", "test");
console.log (afventer client.test ());

Bemærk, at for at være i stand til at generere metoder til klientstubobjektet, skal du videregive alle metodenavne til createClient, som vi gjorde i eksemplet.

Dette er påkrævet, fordi JS ikke har nogen runtime-oplysninger om TypeScript-grænseflader. Jeg kunne implementere det ved hjælp af abstrakte klasser, men jeg kan ikke lide det ¯ \ _ (ツ) _ / ¯.

Bonus! Du kan køre det hele lokalt!

Jeg mener, at det er meget vigtigt at have dit lokale udviklingsmiljø så behageligt som muligt. Dette er grunden til, at jeg også har tilføjet en mulighed for at køre tjenesten og klienten lokalt uden at implementere noget til AWS (se funktioner runService og createClient). Se eksempler på depotet på GitHub.

Resumé

Dette er meget let at gå tabt i de tjenester, skyudbydere tilbyder, og overchineer din infrastruktur.

Jeg vælger altid den mest enkle og eksplicitte løsning, jeg kan tænke på. Husk også altid, at mange teknikker og fremgangsmåder kan genbruges fra andre platforme (ideen om fedt NodeJS Lambda er inspireret af såkaldte fedtkrukker fra Java-verdenen).

Hvis du kunne lide dette emne, så tjek også disse:

  • Du er nødt til at lære, hvordan man gør den bedste serverløse arkitektur
  • Sådan opretter du gratis serverløs CI / CD-rørledning: 3 lette eksempler
  • Sådan nemt replikeres DynamoDB på tværs af regioner
  • Sådan foretages multiregional applikation (og betal nul)
  • Gør enhver Java Web App-serverløs

Kommentarer, likes og aktier er meget værdsatte. Skål!