AWS SAM – Serverless Application Model

Sviluppare efficacemente applicazioni serverless con AWS SAM
Si parla ormai da molto tempo di serverless computing, ovvero di un modello di sviluppo che permette la creazione di applicazioni senza doversi preoccupare di gestire i server su cui queste vengono eseguite. La reale infrastruttura che permette l’esecuzione di queste applicazioni è infatti gestita da un provider di servizi cloud ed è resa astratta e trasparente allo sviluppatore che può così focalizzarsi esclusivamente sullo sviluppo.
I servizi offerti da Amazon Web Services (AWS) sposano pienamente questo paradigma di sviluppo. Un tipico esempio di applicazione serverless sviluppata su AWS è mostrato nell’immagine seguente:
I servizi utilizzati sono i seguenti:
- Cognito user pool: Gestisce gli utenti della piattaforma e offre diverse capabilities tra cui login, logout e gestione password
- API Gateway: Punto di accesso alle API di Backend
- WAF: Web Application Firewall per tutte le richieste in ingresso all’applicazione
- Lambda: Implementazione API di Backend
- DynamoDB: Storage dati di tipo NoSQL
La maggior parte di questi servizi, oltre a non richiedere la gestione di server, presenta un’altra interessante proprietà: il modello di pricing è di tipo pay per use. Ciò significa che il costo di questi servizi è esclusivamente legato al loro utilizzo, al contrario di servizi come EC2 in cui un’istanza di server virtuale genera dei costi fissi, indipendentemente dal fatto che questa venga utilizzata all’1% o al 100%.
Rifacendomi alla mia esperienza con AWS, sento di poter affermare con ragionevole sicurezza che un’applicazione serverless è nella maggior parte dei casi molto più conveniente in termini di costi rispetto ad un’applicazione tradizionale che fa uso di server virtuali.
Sembrerebbe quindi che sposare l’approccio serverless non presenti che benefici, ma purtroppo non è così; alcuni vengono resi più complicati dall’utilizzo di questo paradigma. In questo articolo ci occuperemo in particolare degli aspetti legati alla developer experience.
Una buona developer experience viene facilmente minata dalla mancanza di strumenti per sviluppatori. “Come faccio a gestire infrastruttura e codice contemporaneamente? Come testo continuamente la mia applicazione se questa viene eseguita su cloud? Come posso effettuare facilmente il deploy?” sono le domande che mi sono spesso sentito rivolgere in ambito di sviluppo di applicazioni serverless
Una risposta a queste domande viene fornita da Amazon SAM (Serverless Application Model)
Cos'è Amazon SAM
Amazon SAM è un framework open-source per lo sviluppo di applicazioni serverless in AWS, che comprende principalmente:
- una template specification: per la descrizione dell’applicazione a livello architetturale, cioè di tutti i servizi che la compongono e delle loro interazioni, SAM utilizza dei template Cloudformation. AWS si fa carico di verificare continuamente che lo stato delle risorse AWS descritte nel template sia indentico a quello delle risorse effettivamente deployate su cloud, e di applicare le opportune correzioni in caso i due stati non coincidano. SAM aggiunge delle estensioni a tali template che hanno lo scopo di semplificare la definizione architetturare di un’applicazione serverless
- una SAM Command Line Interface (SAM CLI): tramite una CLI è possibile effettuare validazione, build, test e deploy di applicazioni SAM
Vediamo adesso come creare un’applicazione serverless con SAM, dall’inizializzazione del progetto fino al deploy
Inizializzazione - sam init
Sviluppiamo due semplici API per la memorizzazione e la lettura di TODO.
La CLI di SAM introduce un nuovo comando, sam, di cui andiamo ad analizzare le opzioni principali.
Il comando sam init crea un’applicazione di esempio selezionabile tra alcuni template messi a disposizione da AWS:
Nel nostro caso abbiamo scelto di sviluppare una Serverless API utilizzando nodejs16.x come runtime.
Il risultato sarà la creazione di una struttura base di progetto contenente alcuni file che andiamo ad analizzare.
TEMPLATE CLOUDFORMATION
Il file template.yml che viene creato all’inizializzazione contiene la definizione CloudFormation delle risorse che compongono l’applicazione. Nel nostro caso si tratta principalmente di un ApiGateway che inoltra le chiamate alle API ad una o più Lambda Function che le gestiscono.
Leggendo questo file si può notare che la tipologia di molte risorse è identificata con il prefisso AWS::Serverless
Sono questi i tipi di risorsa che SAM aggiunge alla specifica di CloudFormation. Ma a cosa servono queste estensioni? A semplificare la scrittura di un template CloudFormation di una applicazione serverless.
Prendiamo ad esempio la risorsa AWS::Serverless::Function con cui definiamo la Lambda Function che gestisce le chiamate all’api GetAllTodos. Il template ne specifica, tra le altre cose, il runtime, il percorso del file javascript che implementa la funzione lambda, i ruoli IAM da applicare alla funzione e gli eventi che causano l’esecuzione della lambda function.
Stiamo implementando una Lambda Function che gestisce chiamate ad API, quindi è molto probabile che gli eventi che ne causano l’esecuzione provengano da ApiGateway nel momento in cui un client effettua una chiamata ad un’API esposta tramite questo servizio.
Per questo motivo la sezione Events definisce un evento di tipo Api (type: Api), la cui configurazione prevede la specifica del verbo HTTP e del path dell’API gestita dalla Lambda Function.
Abbiamo specificato da qualche parte qual è l’ApiGateway che inoltra le chiamate alla Lambda Function?
No, perché una risorsa di tipo AWS::Serverless::Function configurata con un evento di tipo Api, prevede la creazione automatica di un ApiGateway anche se questo non viene specificato nello stesso template Cloud Formation. Questo è reso possibile dalle estensioni del template introdotte da SAM. In questo modo la nostra scrittura del template Cloud Formation risulta semplificata. Nel caso in cui la configurazione di default applicata da SAM non soddisfi le nostre esigenze, possiamo comunque creare nello stesso template un ApiGateway custom e metterlo in relazione alla funzioni lambda.
SAM BUILD
Il Comando sam build effettua la build adatta al runtime scelto, preparando un package che contiene da un lato il template Cloud Formation e dall’altro il codice della funzione Lambda.
Questo processo è gestito da SAM, che ci solleva così dalla necessità di creare script per effettuare la build che dovremmo poi customizzare per i diversi linguaggi di programazione utilizzati dalla Lambda Function.
TESTING: SAM ACCELERATE
Inizialmente il testing di applicazioni serverless non era affatto semplice. Principalmente ciò era dovuto al fatto che un’applicazione serverless è costituita da una serie di servizi cloud che interagiscono tra di loro. Anche in una semplice applicazione come quella che stiamo realizzando, stiamo utilizzando almeno 3 servizi cloud diversi (Api Gateway, Lambda, DynamoDB).
In questa situazione ci si imbatte presto nei seguenti problemi:
- “Il mio codice deve essere eseguito all’interno del servizio Lambda Function. Devo quindi per forza effettuarne il deploy su AWS per testare anche una piccola modifica”
- “Per testare il mio codice devo leggerne i log. Questi vengono raccolti da un altro servizio, CloudWatch. Ad ogni deploy devo cercare all’interno di questo servizio i log associati alla Lambda Function appena deployata”
Questo tipo di problemi chiaramente rende lo sviluppo serverless poco appetibile per uno sviluppatore tipicamente abituato ad effettuare parte dello sviluppo e del testing sul proprio laptop.
In un primo momento, AWS ha risolto questi problemi permettendo di emulare sul proprio sistema i servizi Lambda e Api Gateway in modo da poter testare localmente le proprie API. Quest’approccio, seppure migliorativo rispetto alla Developer Experience, risulta comunque limitato in quanto l’emulazione è limitata a soli due servizi. Ci sono casi d’uso più complessi che richiederebbero potenzialmente l’emulazione locale di qualsiasi servizio AWS. Risulta chiaro come questa strada sia difficilmente percorribile.
In seguito SAM ha introdotto SAM ACCELERATE. Il principio che ha guidato l’introduzione di questa nuova feature è quello di non provare ad emulare localmente quanti più servizi possibile, ma di rendere molto più semplice il deploy continuo dell’applicazione su cloud e un controllo più agevole dei log.
Sam Accelerate introduce, ad esempio, il comando sam sync –watch
Con questo comando il framework SAM si mette in ascolto di qualsiasi modifica effettuata sui file del progetto e:
- Se la modifica riguarda un file di una Lambda Function effettua il deploy di quest’ultima
- Se la modifica riguarda il template Cloud Formation riapplica il template
Viene così effettuato un deploy continuo su cloud delle modifiche effettuate all’applicazione. In questo modo non testiamo un’applicazione simulata sul nostro sistema, ma testiamo un’applicazione già deployata su cloud AWS, quindi all’interno di un contesto fatto di reali servizi AWS e che si avvicina il più possibile all’ambiente finale di produzione.
Invocando la funzione Lambda deployata su cloud, ovvero invocando un reale endpoint esposto dal servizio ApiGateway, possiamo anche seguirne i log in maniera semplice, utilizzando il comando sam logs:
Questo comando effettua lo streaming sul nostro terminale dei log prodotti dalla funzione in esecuzione su cloud e raccolti dal servizio Cloudwatch
DEPLOY
Il deploy effettuato tramite SAM Accelerate è consigliato per un ambiente di sviluppo, mentre per gestire un deploy di uno o più ambienti di produzione è necessario utilizzare il comando sam build.
Questo comando richiede la presenza di un file samconfig.toml di cui viene mostrato un esempio in seguito:
In questo file vengono definiti dei profili di deploy, ovvero delle particolari configurazioni che caratterizzano uno deploy specifico.
Potremmo pensare di far coincidere questi profili con gli ambienti di dev, test, prod, oppure con i deploy effettuati per uno specifico cliente, o perchè no, un mix delle due cose. Il poter definire questi profili e poterne attivare uno specifico in fase di build è il meccanismo normalmente utilizzato da strumenti di CI/CD come ad esempio Gitlab CI/CD.
Una discussione completa del framework SAM non può limitarsi a quanto descritto in questo articolo, che mira principalmente as fornire una panoramica generale sui vantaggi dello sviluppo serverless e su come questo può essere reso molto più agevole tramite l’utilizzo di SAM. Esistono tante altre funzionalità di SAM che non sono state affrontate in questo articolo e per le quali consiglio di leggere la doumentazione ufficiale AWS riguardante SAM e l’utilizzo della CLI.
Nel frattempo, happy coding!