Serverless, Development & Deployment – AWS Serverless Application Model (SAM)

23.08.2023Tom Trapp
Tech Serverless Amazon Web Services Function as a Service Pay As You Go

👉 Serverless ist dir noch kein Begriff? Dann findest du hier alles Wissenswerte zum Thema Serverless. 🚀

Im zweiten Teil unserer Serie über Serverless Development & Deployment wollen wir uns das AWS Serverless Application Model (SAM) genauer anschauen. Bereits im ersten Teil haben wir uns mit dem AWS Cloud Development Kit (CDK) auseinandergesetzt. Beide Tools sind sehr ähnlich, jedoch gibt es einige Unterschiede, die ich in diesem Artikel aufzeigen will.

AWS Serverless Application Model (SAM)

AWS SAM, oder Amazon Web Services Serverless Application Model, ist ein Open-Source-Framework, das von AWS entwickelt und erstmals im November 2016 veröffentlicht wurde. AWS SAM hilft Entwicklern, Serverless Anwendungen effizient zu erstellen, zu testen und zu debuggen.

AWS SAM hat folgende Eigenschaften:

  • Serverless-Unterstützung: AWS SAM wurde speziell für die Erstellung von Serverless Anwendungen entwickelt. Es unterstützt AWS-Dienste wie AWS Lambda, Amazon API Gateway und Amazon DynamoDB.
  • Eingebaute Best Practices: Mit AWS SAM können Entwickler Best Practices für Serverless Anwendungen einfach umsetzen. Dies umfasst die Konfiguration von Ereignisquellen und die Verknüpfung von Ressourcen.
  • Lokale Entwicklung und Testen: AWS SAM bietet ein lokales Entwicklungsumfeld, das es Entwicklern ermöglicht, Anwendungen auf ihrem lokalen System zu erstellen und zu testen, bevor sie in die Produktion gehen.
  • Integration mit Entwicklungswerkzeugen: AWS SAM lässt sich in gängige IDEs und CI/CD-Werkzeuge integrieren, um den Entwicklungsprozess zu vereinfachen und zu beschleunigen.
  • Vereinfachtes Deployment: Mit der AWS SAM-Deployment können Entwickler Serverless Anwendungen einfach und zuverlässig bereitstellen. Zusätzlich lässt sich Infrastruktur als Code (IaC) verwenden, um Ressourcen zu definieren und zu verwalten.
  • Vielseitigkeit: Da SAM auf CloudFormation Templates basiert, können “non-SAM-resources” im gleichen Template definiert werden.
  • Erweiterbarkeit: AWS SAM unterstützt die Erweiterung von Vorlagen, sodass Entwickler wiederverwendbare Teile von Anwendungen oder Stack-Konfigurationen erstellen können.

Schauen wir uns das grafisch an, was macht SAM genau:

sam_explained.png

Figure: Quelle: https://www.dev-insider.de/grundlagen-zu-aws-sam-a-843785/ (23.07.2023)

Mit SAM lernen wir das erste deklarative Serverless IaC Framework kennen, sprich die Definition der Ressourcen wird in YAML gemacht und nicht wie bei CDK beispielsweise in Golang. Daher spricht man auch von einem SAM Template.

Schauen wir uns die Projektstruktur genauer an:

sam_explained_detail.png

Figure: Quelle: https://www.sqlshack.com/getting-started-with-the-aws-sam-cli/ (23.07.2023)

Hier sehen wir, dass sich hinter SAM (wie bei CDK auch), ein CloudFormation Stack verbringt. Dieser Stack wird mit dem sam deploy Befehl erstellt.

Hands On

Ziel: Eine Rest-API soll via Lambda Function etwas aus einer DynamoDB lesen. Serverless Land Pattern: API Gateway to Lambda to DynamoDB IaC Tool: AWS Serverless Application Model (SAM) Sprache: Java Aws Services: API Gateway, Lambda, DynamoDB

apigw-lambda-dynamodb-cdk-go

Setup

Zuerst müssen wir die aws-sam-cli installieren, dies geht am einfachsten via brew:

1
2
brew install aws/tap/aws-sam-cli
sam --version

Und wir sind ready! Kein Bootstrapping nötig, da SAM direkt mit CloudFormation arbeitet.

Development

Wie im vorherigen Beispiel clonen wir das Repository (es kann auch das vorhandene genutzt werden) und wechseln in den korrekten Ordner:

1
2
3
git clone https://github.com/aws-samples/serverless-patterns/ 
cd serverless-patterns/apigw-lambda-dynamodb-sam-java
code .

Uns fällt Folgendes auf:

  • Im Ordner src befindet sich unser kompletter Java Sourcecode
  • Hierbei handelt es sich um ein Maven Projekt
  • In der Datei template.yaml sind sämtliche SAM Instruktionen definiert

Local Development

SAM bietet uns die Möglichkeit, unsere Funktionen lokal zu testen. Dazu müssen wir zuerst unsere Java-Funktion mit Maven bauen:

1
mvn clean package

Anschliessend können wir lokal einen Container starten, welcher unsere Lambda-Funktion ausführt:

1
echo ''{"userId": "231deb432f3dd","description": "I have not been listening to decodify yet."}'' | sam local invoke --event -

Leider funktioniert dies so nicht, da wir ein komplettes HTTP Proxy API Gateway Event an unsere lokale Lambda-Funktion senden müssen. Glücklicherweise bietet uns SAM auch hierfür eine Lösung:

1
sam local generate-event apigateway http-api-proxy > event.json

Mit diesem Befehl generieren wir ein Event, welches wir dann an unsere Funktion senden können. Nun können wir im event.json im Property body unser Json spezifizieren, dies sollte dann so aussehen:

1
  "body": "{\"userId\": \"231deb432f3dd\",\"description\": \"I have not been listening to decodify yet.\"}",

Anschliessend invoken wir unsere Funktion mit dem Event:

1
sam local invoke -e event.json

Nun sehen wir, unsere Funktion wurde korrekt invokiert, da wir einen Fehler bekommen, dass unsere DynamoDB nicht kontaktiert werden kann.

Selbstverständlich könnten wir uns jetzt entweder einen Mock Service in Java schreiben, welcher die DynamoDB abstrahiert. Oder wir nutzen Docker und starten eine lokalen DynamoDB und lassen unsere Funktion damit kommunizieren. Beides würde aber den Rahmen hier sprengen, da wir uns auf den Serverless Teil fokussieren wollen.

Grundsätzlich haben wir aber gesehen, wie man mit SAM ein Local Development machen könnte, inkl. effektiven lokalen REST Calls. Auch hier würde sich alternativ der Test-Driven-Development Ansatz anbieten.

Deployment

Genug Local Development Action, nun wollen wir unser kleines Java Serverless Programm deployen! Zur Sicherheit bauen wir unser Programm nochmals:

1
mvn clean package

Anschliessend können wir dann unser sam deploy Ausführen und das AWS S3 Bucket angeben, wo sich unsere Lambda-Funktion bzw. deren gebauter Sourcecode befindet.

1
sam deploy --guided

Wir werden nun nach unterschiedlichen Input Parametern gefragt.

sam_deploy.png

Glücklicherweise können wir diese Werte in einer samconfig.toml speichern, damit wir diese nicht jedes Mal eingeben müssen.

Sobald wir sam deploy --guided einmalig ausgeführt haben können wir in Zukunft nur sam deploy ausführen und die Configs auf samconfig.toml nutzen.

Anschliessend wird uns noch aufgezeigt, was genau deployed wird:

sam_deploy_2.png

Nun wurde unser Sam Template erfolgreich deployed. Da wir in unserer template.yaml definiert haben, dass unsere API Gateway URL ausgegeben werden soll, können wir uns diese wieder zwischenspeichern:

1
export APIGW_REST_ENDPOINT=https://<app-id>.execute-api.eu-central-1.amazonaws.com/dev/ticket

Weitere nützliche Commands:

  • sam build: Kompiliert den Code für alle Funktionen im Projekt und speichert sie in einem Bucket für den Upload in AWS Lambda.
  • sam package: Packt die Anwendung und die Dependencies in ein CloudFormation-kompatibles Paket, das für die spätere Bereitstellung verwendet werden kann.
  • sam local invoke: Testet eine Funktion lokal, indem sie mit einem Ereignis getriggert wird.
  • sam logs: Zeigt die Protokolle für eine bestimmte Funktion an.
  • sam validate: Überprüft die Vorlage auf gültige Syntax und Semantik.

Testing

Nun, nachdem wir unseren SAM Stack deployed haben, wollen wir diesem via Curl testen:

1
2
curl -X POST $APIGW_REST_ENDPOINT -H "Content-Type: application/json" -d '{"userId": "John","description": "I have not been listening to decodify yet."}'
curl -X POST $APIGW_REST_ENDPOINT -H "Content-Type: application/json" -d '{"userId": "Maria","description": "What is decodify?"}'

Beide Calls gehen direkt mit HTTP 200 Success durch, sehr cool! 🔥

Anschliessend können wir uns wieder den Inhalt unserer DynamoDB anschauen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
aws dynamodb scan --table-name tickets

---
{
    "Items": [
        {
            "description": {
                "S": "What is decodify?"
            },
            "userId": {
                "S": "Maria"
            },
            "ticketId": {
                "S": "3fe863f8-78d6-4447-9f44-9c3c443010df"
            }
        },
        {
            "description": {
                "S": "I have not been listening to decodify yet."
            },
            "userId": {
                "S": "John"
            },
            "ticketId": {
                "S": "4425a3ad-463e-4666-bf6b-a272308979b9"
            }
        }
    ],
    "Count": 2,
    "ScannedCount": 2,
    "ConsumedCapacity": null
}

Das wars auch schon, wir haben erfolgreich eine Rest-API mit Lambda und DynamoDB via SAM deployed und getestet.

Cleanup

1
2
sam delete --stack-name ticket-stack
aws s3 rb s3://b-nova-sam-example-bucket --force

TLDR

SAM ist aktuell mit über 250 Patterns auf Serverless Land das IaC Tool, welches dort am meisten eingesetzt wird.

Vorteile

  • Deklarativer Ansatz
  • Einfache Syntax für das Definieren von Serverless-Ressourcen
  • Integriert sich nahtlos in AWS CloudFormation
  • Bietet eine lokale Entwicklungsumgebung für schnelleres Iterieren

Nachteile

  • Unterstützt nur AWS als Cloud-Plattform
  • Lokales Mocking nötig, nicht alle Services können lokal emuliert werden

SAM vs. CDK

Beide IaC Tools wollen das Gleiche erreichen, AWS Ressourcen einfach und schnell deployen. SAM ist auf den Serverless Einsatz spezialisiert, was es sehr einfach macht, eine Serverless Applikation zu deployen. Der deklarative Ansatz macht SAM ebenfalls etwas einfacher und nutzbarer als CDK. Grundsätzlich ist der Einsatz aber Use-Case-abhängig; sollte es sich um eine Serverless Applikation handeln, würde ich SAM bevorzugen.

Nun haben wir das AWS Serverless Application Model (SAM) kennengelernt und wissen, wie wir damit eine REST-API mit Lambda und DynamoDB deployen können. Im nächsten TechUp der Serien wagen wir den Sprung in die Open Source Welt, entfernen uns vom Vendor Lock-In und schauen uns das Serverless Framework genauer an. Bleib dran! 🔥

Tom Trapp

Tom Trapp – Problemlöser, Innovator, Sportler. Am liebsten feilt Tom den ganzen Tag an der moderner Software und legt viel Wert auf objektiv sauberen, leanen Code.