Eine containerisierte Web-App auf AWS Lambda betreiben
Wie md2docx von einem VPS-Container zu serverless auf AWS für ~0 $ wechselte — ohne eine Zeile App-Code zu ändern, samt der drei Stolperfallen, vor denen niemand warnt.
md2docx lief zufrieden als Docker-Container auf einem VPS. Ich habe es aus zwei Gründen zu serverless auf AWS umgezogen: im Leerlauf ~0 $ zahlen und die Plattform richtig lernen. Die Überraschung war, dass sich der Anwendungscode überhaupt nicht änderte. Die Reibung lag überall sonst.
Die App ändert sich nicht — ein Adapter schon
Lambda spricht Events, Express spricht HTTP. Der AWS Lambda Web Adapter verbindet beides: Leg seine Binärdatei als Lambda-Extension ins Container-Image, und er übersetzt jeden Invoke in einen normalen HTTP-Request an deinen Server auf localhost. Das Dockerfile bekommt eine Zeile dazu; der Server bleibt genau so, wie er auf dem Laptop läuft. Ich habe das Image für arm64 gebaut (Graviton — etwa 20 % günstiger), nach ECR gepusht und Lambda es hinter einer eingebauten Function URL ausliefern lassen.
Drei Stolperfallen
Dann wehrte sich die Plattform.
- Die Region unterstützte keine Function URLs. Das Erstellen scheiterte mit
AccessDeniedException: Unable to determine service/operation name to be authorized— was nach „Rechte-Bug“ schreit, aber eigentlich „Feature in dieser Region nicht verfügbar“ heißt. Eine neuere Region hatte es schlicht nicht. Lösung: eine Tier-1-Region nehmen. - Neue AWS-Konten blockieren öffentliche Function URLs standardmäßig. Selbst mit einer lehrbuchmäßig korrekten Resource-Policy, die
lambda:InvokeFunctionUrlfür alle erlaubt, kam bei jedem Request ein403 Forbidden. Der sich undokumentiert anfühlende Fix: zusätzlichlambda:InvokeFunctionfür*gewähren. - CloudFront davor, aber OAC signiert keine POST-Bodies. Um den Verkehr durch das CDN zu zwingen, probierte ich Origin Access Control mit IAM-Auth — und
POSTbrach sofort, weil OAC den Request-Body nicht in seine SigV4-Signatur aufnimmt und Lambda unsignierte Payloads ablehnt. Für eine App, deren ganze Aufgabe das POSTen von Markdown ist, ist das tödlich. Ich wechselte zu einem gemeinsamen Geheimnis: CloudFront fügt einen Header ein, und die App lehnt alles ohne ihn ab.
Was es kostet
Lambda und CloudFront haben beide dauerhafte Free Tiers — nicht die Sechs-Monats-Credits — von 1 Mio. Requests + 400 000 GB-Sekunden und 1 TB Egress pro Monat. Ein Hobby-Konverter lebt mit Reserve darin, also liegt die Rechnung praktisch bei 0 $, und im Leerlauf skaliert er auf null. Der Preis ist Latenz: Der erste Request nach einer ruhigen Phase wartet ein paar Sekunden auf den Kaltstart. Für ein Tool, das man gelegentlich nutzt, ist das ein guter Tausch.
Serverless machte die App nicht einfacher — es machte sie im Ruhezustand kostenlos und den Betrieb zum Problem von jemand anderem. Der Haken war nie der Code; es waren das Dutzend kleiner Defaults drumherum.