So machen Sie eine NodeJS-App serverlos

Ich hoffe, Sie lieben Serverless genauso wie ich, denn dies ist ein weiterer Beitrag zu diesem Thema.

Wenn es sich um eine einfache REST-API ohne Server handelt, ist Ihr Setup in AWS: Lambda + API Gateway ziemlich offensichtlich.

Aber wie wäre es mit anderen (Mikro-) Diensten, die Ihr Backend möglicherweise hat? Sie wissen, es ist nicht die beste Idee, Ihren gesamten Anwendungscode in eine einzige monolithische AWS Lambda-Funktion zu integrieren.

Die Herausforderung

Wir möchten Anwendungsmodule einfach als serverlose Mikrodienste bereitstellen, die auch miteinander kommunizieren müssen. Vorzugsweise sollte die Kommunikation zwischen Diensten durch eine Art ACL geregelt werden.

Versuch 1. API Gateway

Dies ist der erste Gedanke, den ich hatte, als ich versuchte, das Problem zu lösen: Legen Sie einfach alle Microservices über API Gateway offen. Das Problem ist… Die erstellten APIs sind öffentlich.

Warum ist das ein Problem? Zum Beispiel möchten wir nicht, dass ein Abrechnungsservice für die ganze Welt verfügbar ist, auch wenn der Zugriff durch eine Autorisierung eingeschränkt wird.

Nun, Sie können die API privat machen, aber die Sicherheitsrichtlinien sind ziemlich begrenzt:

Sie können API-Gateway-Ressourcenrichtlinien verwenden, um das sichere Aufrufen Ihrer API durch Folgendes zu ermöglichen:
* Benutzer eines bestimmten AWS-Kontos
* Angegebene Quell-IP-Adressbereiche oder CIDR-Blöcke
* Angegebene Virtual Private Clouds (VPCs) oder VPC-Endpunkte (in einem beliebigen Konto)

Dies macht es ziemlich schwierig, die Kommunikation zwischen solchen Diensten zu steuern. Die einzige Möglichkeit, dies hier zu tun, besteht darin, Dienste in separate VPCs zu integrieren, was zu viel Arbeit bedeutet.

Versuch 2. Lambda

Warum stellen wir nicht einfach jeden Microservice in einen separaten AWS Lambda? Wird dies das Problem lösen?

Ja, in der Tat handelt es sich um einen serverlosen Mikrodienst, und Sie können IAM-Richtlinien verwenden, um die Zugriffe zwischen Diensten zu optimieren. Dies ist jedoch nicht „einfach“.

Ich weiß, dass es heutzutage ganz normal ist, eine winzige Funktion als Bereitstellungseinheit zu haben. Für den Fall, dass Ihr Service mehr als einen Endpunkt / eine Methode / eine Funktion hat, ist es in Ordnung, ihn als mehrere Lambdas bereitzustellen.

Ich verstehe die Vorteile, aber Sie opfern die einfache Wartung und Entwicklung. Außerdem mag ich die Idee, einen Dienst als eine Reihe von Lambda-Funktionen bereitstellen zu lassen, nicht wirklich. Stellen Sie sich vor, mehrere separate Funktionen, die sich mit der Abrechnung befassen? Es ist kein begrenzter Kontext mehr. Es gibt zwar Fälle, in denen eine solche Granularität nützlich sein kann, dies ist jedoch ein seltener Fall.

Versuch 3. Fettes Lambda

Können wir tatsächlich eine Reihe von Endpunkten als ein einziges Lambda bereitstellen (natürlich ohne API-Gateway)?

Wenn wir dies tun könnten, würden wir alle Vorteile der vorherigen Option nutzen, aber wir könnten auch die Granularität unserer Bereitstellungseinheiten auswählen.

Ich möchte Folgendes: Jeder implementierbare Service sollte ein einfaches, altes JS-Objekt mit Methoden sein. Dies ist recht einfach zu erreichen, indem Sie ein paar Zeilen Klebercode zwischen Ihrem Objekt und AWS Lambda einfügen.

Hier ist meine Implementierung davon: aws-rpc. Dieses nodejs-Modul macht die lambdaHandler-Funktion verfügbar, bei der Sie nur ein Objekt übergeben, und es wird automatisch allen Benutzern zugänglich gemacht, die auf das Lambda zugreifen können:

import {lambdaHandler} from 'aws-rpc';
{TestServiceImpl} aus './TestServiceImpl' importieren;
// Dies ist Ihre Bereitstellungseinheit
// Dies ist, was Sie als Lambda-Handlerfunktion angeben
export const handler = lambdaHandler (neues TestServiceImpl ());

Jetzt können Sie den „Handler“ einfach als AWS Lambda bereitstellen. So rufen Sie die Methoden auf:

{TestService} aus './TestService' importieren;
const client = warte auf createClient  ("LambdaName", "test");
console.log (warte auf client.test ());

Bitte beachten Sie, dass Sie, um Methoden für das Client-Stub-Objekt generieren zu können, alle Methodennamen wie im Beispiel an createClient übergeben müssen.

Dies ist erforderlich, da JS keine Laufzeitinformationen zu TypeScript-Schnittstellen hat. Ich könnte es mit abstrakten Klassen implementieren, aber ich mag es nicht ¯ \ _ (ツ) _ / ¯.

Bonus! Sie können alles lokal ausführen!

Ich glaube, es ist sehr wichtig, dass Ihre lokale Entwicklungsumgebung so komfortabel wie möglich ist. Aus diesem Grund habe ich auch die Möglichkeit hinzugefügt, den Service und den Client lokal auszuführen, ohne dass etwas für AWS bereitgestellt werden muss (siehe Funktionen runService und createClient). Beispiele finden Sie im Repository von GitHub.

Zusammenfassung

Dies ist sehr einfach, wenn Sie sich in den Diensten verlieren, die Cloud-Anbieter anbieten, und Ihre Infrastruktur überarbeiten.

Ich wähle immer die einfachste und expliziteste Lösung, die mir einfällt. Denken Sie auch immer daran, dass viele Techniken und Praktiken von anderen Plattformen aus wiederverwendet werden können (die Idee des fetten NodeJS Lambda ist inspiriert von sogenannten fetten Gläsern aus der Java-Welt).

Wenn Ihnen dieses Thema gefallen hat, lesen Sie auch Folgendes:

  • Sie müssen lernen, wie Sie die beste Architektur ohne Server erstellen
  • So erstellen Sie eine kostenlose serverlose CI / CD-Pipeline: 3 einfache Beispiele
  • Einfache Replikation von DynamoDB über Regionen hinweg
  • Wie man eine multiregionale Anwendung erstellt (und Null bezahlt)
  • Machen Sie Java Web App Serverless

Kommentare, Likes und Shares werden sehr geschätzt. Prost!