Express/Fastify Apps mit dem Serverless Framework auf AWS Lambda bereitstellen
Min-jun Kim
Dev Intern · Leapcell

Einleitung
In der heutigen schnelllebigen, Cloud-nativen Landschaft suchen Entwickler ständig nach Wegen, Anwendungen effizienter, kostengünstiger und skalierbarer zu erstellen und bereitzustellen. Herkömmliche serverbasierte Bereitstellungen gehen oft mit dem Aufwand der Verwaltung von Infrastruktur, Skalierung und Patches einher. Serverless Computing, insbesondere mit AWS Lambda, bietet eine überzeugende Alternative, indem es die Serververwaltung abstrahiert und es Entwicklern ermöglicht, sich ausschließlich auf ihre Anwendungslogik zu konzentrieren. Die Migration bestehender monolithentischer oder sogar microservice-basierter Express- oder Fastify-Anwendungen zu einer Serverless-Architektur kann jedoch entmutigend erscheinen. Die gute Nachricht ist, dass Sie Ihren gesamten Codebase nicht immer neu schreiben müssen. Dieser Artikel untersucht, wie Sie Ihre Express- oder Fastify-Anwendungen mühelos mit dem Serverless Framework auf AWS Lambda bereitstellen können, um die Vorteile von Serverless zu nutzen, ohne Ihre vertrauten JavaScript-Frameworks aufzugeben.
Die Serverless-Transformation verstehen
Bevor wir uns mit dem Bereitstellungsprozess befassen, lassen Sie uns einige Kernkonzepte klären, die entscheidend sind, um zu verstehen, wie unsere herkömmlichen Webanwendungen in das Serverless-Paradigma passen.
Kernterminologie
- AWS Lambda: Ein Compute-Service, mit dem Sie Code ausführen können, ohne Server bereitstellen oder verwalten zu müssen. Sie zahlen nur für die von Ihnen verbrauchte Compute-Zeit.
- API Gateway: Ein vollständig verwalteter Dienst, der es Entwicklern erleichtert, APIs jeder Größe zu erstellen, zu veröffentlichen, zu warten, zu überwachen und zu sichern. Er fungiert als "Haustür" für Anwendungen, die auf Lambda laufen.
- Serverless Framework: Ein Open-Source-CLI-Tool, das Ihnen hilft, Serverless-Anwendungen auf verschiedenen Cloud-Anbietern, einschließlich AWS, zu erstellen, bereitzustellen und zu verwalten. Es vereinfacht die Definition und Bereitstellung von Serverless-Ressourcen.
- Lambda Proxy Integration: Ein spezifischer Integrationstyp in API Gateway, der es API Gateway ermöglicht, die gesamte Anfrage "as-is" an die Backend-Lambda-Funktion weiterzugeben und die gesamte Lambda-Antwort "as-is" an den Client zurückzugeben. Dies ist entscheidend für Frameworks wie Express oder Fastify, die direkten Zugriff auf HTTP-Anforderungs- und -Antwortobjekte erwarten.
serverless-http
: Ein leichtgewichtiges Node.js-Modul, das als Brücke zwischen HTTP-Frameworks (wie Express, Fastify) und dem Event-Objekt von AWS Lambda fungiert. Es passt die Lambda-Event-Struktur an die Standard-Node.jshttp.IncomingMessage
- undhttp.ServerResponse
-Objekte an, die diese Frameworks erwarten.
Funktionsweise
The fundamental idea is to "wrap" your Express or Fastify application within an AWS Lambda function. When a request comes in through API Gateway, instead of directly invoking your Lambda function with a simple event, we configure API Gateway to use Lambda Proxy Integration. This means API Gateway sends the raw HTTP request details (headers, body, method, path, query parameters) to your Lambda function as a JSON object.
Inside your Lambda function, the serverless-http
library plays a pivotal role. It intercepts this API Gateway proxy event, transforms it into an http.IncomingMessage
and http.ServerResponse
object, and then passes these to your Express or Fastify application's request handler. Your application processes the request as it normally would. Once your application generates a response, serverless-http
captures that, transforms it back into the format API Gateway expects (a JSON object with statusCode
, headers
, and body
), and returns it to API Gateway, which then sends it back to the client.
Diese Architektur ermöglicht, dass Ihre bestehende Express/Fastify-Logik fast unverändert ausgeführt wird und von Lambdas Auto-Skalierung, dem Pay-per-Execution-Modell und dem reduzierten operativen Aufwand profitiert.
Praktisches Bereitstellungsbeispiel
Lassen Sie uns ein Beispiel mit einer Express-Anwendung durchgehen. Der Prozess für Fastify ist sehr ähnlich.
1. Projekt-Setup
Zuerst initialisieren Sie ein neues Node.js-Projekt.
mkdir express-lambda-app cd express-lambda-app npm init -y
2. Abhängigkeiten installieren
Installieren Sie Express und serverless-http
. Wir werden auch serverless
global oder lokal installieren.
npm install express serverless-http npm install -g serverless # oder npm install --save-dev serverless
3. Ihre Express-Anwendung erstellen (app.js
)
Erstellen Sie eine Datei namens app.js
mit Ihrer Express-Anwendungslogik.
// app.js const express = require('express'); const app = express(); const port = 3000; // Dieser Port wird in Lambda nicht verwendet, ist aber für lokales Testen nützlich app.use(express.json()); // Zum Parsen von application/json app.get('/', (req, res) => { res.send('Hello from Express on Lambda!'); }); app.get('/users/:id', (req, res) => { const userId = req.params.id; res.json({ message: `Fetching user with ID: ${userId}` }); }); app.post('/data', (req, res) => { const data = req.body; res.json({ message: 'Data received', data: data }); }); // Für lokales Testen if (process.env.NODE_ENV !== 'production') { app.listen(port, () => { console.log(`Local Express app listening at http://localhost:${port}`); }); } module.exports = app;
4. Ihren Lambda-Handler erstellen (handler.js
)
Diese Datei enthält die tatsächliche Lambda-Funktion, die serverless-http
verwendet.
// handler.js const serverless = require('serverless-http'); const app = require('./app'); // Wickeln Sie die Express-App mit serverless-http ein module.exports.handler = serverless(app);
5. Serverless konfigurieren (serverless.yml
)
Dies ist das Herzstück Ihrer Serverless-Bereitstellung. Erstellen Sie eine serverless.yml
-Datei.
# serverless.yml service: express-lambda-app frameworkVersion: '3' provider: name: aws runtime: nodejs18.x # Wählen Sie eine geeignete Node.js-Laufzeit region: us-east-1 # Ihre bevorzugte AWS-Region memorySize: 128 # Minimale Speichergröße stage: dev # Bereitstellungsphase (z. B. dev, prod) environment: # Umgebungsvariablen für Ihre Lambda-Funktion NODE_ENV: production apiGateway: # Diese Einstellung ist entscheidend, damit API Gateway rohe Anfragen an Lambda weiterleitet minimumCompressionSize: 1024 # Gzip-Komprimierung für Antworten größer als 1 KB aktivieren functions: api: handler: handler.handler # Verweist auf handler.js und dessen 'handler'-Export events: - http: # Dies definiert einen API Gateway HTTP-Endpunkt path: / # Fängt Anfragen an den Root-Pfad ab method: any # Fängt jede HTTP-Methode ab (GET, POST, PUT, DELETE, usw.) cors: true # Ermöglicht CORS für diesen Endpunkt - http: path: /{proxy+} method: any cors: true
Erklärung von serverless.yml
:
service
: Der Name Ihres Serverless-Dienstes.frameworkVersion
: Gibt die verwendete Version des Serverless Frameworks an.provider
: Konfiguriert den Cloud-Anbieter (in diesem Fall AWS).runtime
: Die Node.js-Version für Ihre Lambda-Funktion.region
: Die AWS-Region, in der Ihre Ressourcen bereitgestellt werden.memorySize
: Zugewiesener Speicher für die Lambda-Funktion.stage
: Die Bereitstellungsphase.environment
: Umgebungsvariablen, die innerhalb Ihrer Lambda zugänglich sind.apiGateway
: Spezifische API Gateway-Konfigurationen.minimumCompressionSize
ist gut für die Leistung.
functions
: Definiert Ihre AWS Lambda-Funktionen.api
: Der Name unserer Lambda-Funktion.handler
: Gibt die Datei und den Export der Funktion an (z. B. denhandler
-Export vonhandler.js
).events
: Hier verknüpfen wir unsere Lambda mit einem API Gateway HTTP-Endpunkt.- Die beiden
http
-Events sind entscheidend: eines für den Root-Pfad/
und ein weiteres für alle nachfolgenden Pfade/{proxy+}
. Dies stellt sicher, dass alle Anfragen an Ihr API Gateway an Ihre einzelne Lambda-Funktion weitergeleitet und von Ihrer Express-App verarbeitet werden.proxy+
ist ein Wildcard, der alle Pfade nach dem Basis-Pfad erfasst. method: any
ermöglicht es Ihrer Express-App, alle HTTP-Methoden zu verarbeiten.cors: true
aktiviert Cross-Origin Resource Sharing, was oft für Frontend-Anwendungen unerlässlich ist.
- Die beiden
6. Ihre Anwendung bereitstellen
Schließlich stellen Sie Ihre Anwendung mit der Serverless Framework CLI bereit:
serverless deploy
Die CLI packt Ihren Code, erstellt die erforderlichen AWS-Ressourcen (Lambda-Funktion, API Gateway-Endpunkt, IAM-Rollen) und liefert Ihnen nach erfolgreicher Bereitstellung die API Gateway-Endpunkt-URL.
7. Ihre Anwendung testen
Nach der Bereitstellung können Sie über die bereitgestellte API Gateway-URL auf Ihre Express-Anwendung zugreifen.
Wenn Ihre URL beispielsweise https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
lautet:
GET https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
gibt "Hello from Express on Lambda!" zurück.GET https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/users/123
gibt{"message": "Fetching user with ID: 123"}
zurück.POST https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/data
mit einem JSON-Body wie{ "name": "Alice" }
gibt{"message": "Data received", "data": {"name": "Alice"}}
zurück.
Beispiel für eine Fastify-Anwendung
Der Prozess für Fastify ist fast identisch.
1. Abhängigkeiten installieren
npm install fastify serverless-http # Und serverless wie zuvor
2. Ihre Fastify-Anwendung erstellen (fastify-app.js
)
// fastify-app.js const fastify = require('fastify'); const app = fastify({ logger: true }); // Logger für bessere Entwicklungserfahrung aktivieren app.get('/', async (request, reply) => { return { message: 'Hello from Fastify on Lambda!' }; }); app.get('/users/:id', async (request, reply) => { const userId = request.params.id; return { message: `Fetching user with ID: ${userId}` }; }); app.post('/data', async (request, reply) => { const data = request.body; return { message: 'Data received', data: data }; }); // Für lokales Testen if (process.env.NODE_ENV !== 'production') { app.listen({ port: 3000 }, (err, address) => { if (err) { app.log.error(err); process.exit(1); } console.log(`Local Fastify app listening at ${address}`); }); } module.exports = app;
3. Ihren Lambda-Handler erstellen (fastify-handler.js
)
// fastify-handler.js const serverless = require('serverless-http'); const app = require('./fastify-app'); // Wickeln Sie die Fastify-App mit serverless-http ein (stellen Sie sicher, dass sie zuerst initialisiert ist) // Hinweis: serverless-http benötigt die Fastify-Instanz, nicht nur die Funktion, die sie erstellt. // Wir müssen auch das Ready-Promise für Fastify awaiten, bevor wir es an serverless-http übergeben. const handler = async (event, context) => { await app.ready(); // Sicherstellen, dass Fastify-Plugins geladen sind const serverlessHandler = serverless(app); return serverlessHandler(event, context); }; module.exports.handler = handler;
Wichtiger Hinweis für Fastify: serverless-http
erwartet eine bereits initialisierte Anwendungsinstanz. Für Fastify sollten Sie normalerweise await app.ready()
aufrufen, um sicherzustellen, dass alle Plugins geladen sind, bevor serverless-http
mit der Verarbeitung von Anfragen beginnt. Dies wird durch das Umschließen von serverless(app)
in einer async
-Funktion gehandhabt.
4. Serverless (serverless.yml
) für Fastify konfigurieren
Aktualisieren Sie einfach den handler
-Pfad in serverless.yml
:
# serverless.yml (Ausschnitt für Fastify) functions: api: handler: fastify-handler.handler # Verweist auf fastify-handler.js und dessen 'handler'-Export events: - http: path: / method: any cors: true - http: path: /{proxy+} method: any cors: true
Dann serverless deploy
wie zuvor.
Anwendungsszenarien und Best Practices
Dieser Ansatz ist ideal für:
- Migration bestehender Webanwendungen: Keine Notwendigkeit für vollständige Neufassungen.
- Erstellung von APIs mit etablierten Frameworks: Nutzen Sie die robusten Funktionen von Express oder Fastify in einer Serverless-Umgebung.
- Schnelles Prototyping: Stellen Sie schnell eine API bereit, ohne Server verwalten zu müssen.
- Microservices: Jeder Microservice kann als separate Express/Fastify-App auf Lambda bereitgestellt werden.
Best Practices:
- Kaltstarts von Lambda im Auge behalten: Obwohl
serverless-http
effizient ist, können komplexe Express/Fastify-Apps immer noch zu Kaltstart-Strafen führen. Erwägen Sie Provisioned Concurrency für leistungsoptimierte Endpunkte. - Abhängigkeiten optimieren: Bündeln Sie nur notwendige Abhängigkeiten mit Tools wie
webpack
oderesbuild
mit Serverless Framework-Plugins, um die Größe des Deployment-Pakets und die Kaltstartzeiten zu reduzieren. - Zustandsverwaltung: Denken Sie daran, dass Lambda-Funktionen zustandslos sind. Verwenden Sie externe Dienste wie DynamoDB, RDS, S3 oder ElastiCache für persistente Datenspeicherung.
- Protokollierung und Überwachung: Nutzen Sie AWS CloudWatch für Protokolle und Metriken.
- Fehlerbehandlung: Implementieren Sie eine robuste Fehlerbehandlung innerhalb Ihrer Express/Fastify-App und erwägen Sie die Verwendung von Diensten wie AWS X-Ray für verteilte Tracing.
- Umgebungsvariablen: Verwenden Sie den Abschnitt
environment
des Serverless Frameworks inserverless.yml
oder AWS Secrets Manager/Parameter Store für sensible Konfigurationen.
Fazit
Die Bereitstellung von Express- oder Fastify-Anwendungen auf AWS Lambda mit dem Serverless Framework und serverless-http
bietet einen leistungsstarken Weg zur Akzeptanz von Serverless. Sie ermöglicht es Entwicklern, die Skalierbarkeit, Kosteneffizienz und operative Einfachheit von Lambda zu nutzen, ohne ihre bevorzugten JavaScript-Web-Frameworks aufgeben zu müssen. Durch das Verständnis des Integrationsmechanismus und die Befolgung bewährter Praktiken können Sie Ihre bestehenden Serverless-Webanwendungen erfolgreich umstellen oder neue erstellen, und das mit minimalem Aufwand. Dieser Ansatz ermöglicht es Entwicklern, sich auf die Entwicklung von Features zu konzentrieren und nicht auf die Verwaltung von Infrastruktur.