{"id":284,"date":"2018-09-25T12:48:07","date_gmt":"2018-09-25T10:48:07","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=284"},"modified":"2021-03-17T12:13:22","modified_gmt":"2021-03-17T11:13:22","slug":"go-serverless-pt2","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/go-serverless-pt2\/","title":{"rendered":"Go Serverless! Parte 2: l\u2019infrastruttura per l\u2019applicazione di file sharing"},"content":{"rendered":"
Leggi la prima parte<\/a> | Leggi la terza parte<\/a><\/p>\n Con la sempre maggiore diffusione dello sviluppo Serverless, \u00e8 di fondamentale importanza comprendere come sfruttarne tutti i vantaggi per poter realizzare applicazioni scalabili<\/strong> e resilienti<\/strong>.<\/p>\n Questa \u00e8 la seconda parte della serie di 3 articoli (qui<\/a> trovate la prima parte) su come costruire una piattaforma di file sharing completamente serverless<\/strong>. In questo articolo <\/span>andremo a realizzare<\/span> l\u2019infrastruttura, approfondendo gli aspetti fondamentali per una corretta ed efficace implementazione.<\/span><\/p>\n Come anticipato nell\u2019<\/span>articolo <\/span><\/a>precedente, oltre all\u2019infrastruttura dell\u2019applicazione andremo anche a realizzare le pipeline di Continuous Integration e Continuous Delivery<\/strong>. <\/span><\/p>\n Cominciamo con il primo dei due punti.<\/span><\/p>\n Non tratteremo qui del codice applicativo e degli argomenti correlati allo sviluppo, che saranno descritti in modo approfondito nel prossimo articolo. Per testare l\u2019infrastruttura impiegheremo delle semplici pagine statiche e una funzione lambda di test.<\/span><\/p>\n Iniziamo con l\u2019analisi della soluzione presentata nella prima parte della serie.<\/span><\/p>\n Il front-end \u00e8 una single page application di cui effettueremo il deploy su S3 e che sar\u00e0 servita mediante CloudFront<\/strong>. Il back-end invece \u00e8 una API REST realizzata con API Gateway<\/strong> e Lambda<\/strong>.<\/span><\/p>\n Per realizzare l\u2019infrastruttura occorre effettuare il provisioning e la configurazione delle seguenti risorse AWS:<\/span><\/p>\n Per prima cosa andiamo a creare un bucket S3 dove caricare l\u2019applicazione javascript e html per il front-end.<\/span><\/p>\n Lo stesso bucket sar\u00e0 la sorgente per la distribuzione di CloudFront.<\/span><\/p>\n Il bucket pu\u00f2 essere privato, configureremo la distribuzione in modo da consentire a CloudFront l\u2019accesso al bucket S3.<\/span><\/p>\n Dopo \u00e8 possibile caricare un semplice file di prova, che useremo per verificare il corretto funzionamento del front-end.<\/span><\/p>\n <\/p>\n <\/p>\n Salviamo questo file come \u201cindex.html<\/strong>\u201d e carichiamolo nel bucket appena creato.<\/span><\/p>\n Una volta ultimate le operazioni per la creazione del bucket S3 occorre creare una distribuzione CloudFront<\/strong> che lo utilizzi come origine. Questo per distribuire il file che abbiamo caricato, che non \u00e8 al momento accessibile.<\/span><\/p>\n Nella configurazione della distribuzione \u00e8 importante abilitare l\u2019opzione \u201cRestrict Bucket Access<\/strong>\u201d per mantenere il bucket S3 privato. <\/span><\/p>\n Al fine di consentire al servizio CloudFront di accedere al bucket in lettura bisogna provvedere ad attivare e configurare l\u2019opzione \u00a0\u201cOrigin Access Identity<\/strong>\u201d; \u00e8 possibile delegare al wizard la creazione di una Access Identity e l\u2019aggiornamento della Bucket Policy.<\/span><\/p>\n Per quanto riguarda le impostazioni del comportamento di caching<\/strong> attiviamo il redirect di http su https e abilitiamo la compressione automatica dei contenuti serviti per migliorare le performance.<\/span><\/p>\n Non bisogna dimenticare di indicare quale file servire di default se non indicato, ed impostarlo ad index.html<\/span><\/p>\n Il processo di creazione della distribuzione pu\u00f2 richiedere diversi minuti.<\/span> Quando la distribuzione sar\u00e0 pronta \u00e8 possibile ottenere l\u2019url pubblico e testare il deploy del front-end navigando a quell\u2019indirizzo.<\/span><\/p>\n Dovrebbe essere visualizzata la pagina di esempio che abbiamo caricato nei passaggi precedenti.<\/span><\/p>\n Il front-end \u00e8 quindi pronto.<\/strong> Il contenuto del bucket viene servito in modo efficiente e cost effective attraverso la CDN; per aggiornare l\u2019applicazione basta caricarla su S3. <\/span><\/p>\n Attenzione! se si modificano file gi\u00e0 presenti occorre invalidare la cache della distribuzione per vedere gli aggiornamenti.<\/span><\/em><\/p>\n Passiamo ora alla realizzazione dell\u2019infrastruttura del back-end del nostro sistema di file sharing.<\/span><\/p>\n Come prima cosa possiamo creare una funzione lambda<\/strong> che utilizzeremo ai fini di test.<\/span><\/p>\n Come abbiamo gi\u00e0 detto, non ci occuperemo adesso dell\u2019applicazione vera e propria, ma solo di costruire tutte le parti dell\u2019infrastruttura. Questa funzione non far\u00e0 altro che restituire uno stato di successo ed un messaggio.<\/span><\/p>\n Procediamo quindi con la creazione della funzione impostando Python come Runtime e assegnando un ruolo con permessi di base.<\/span><\/p>\n <\/p>\n <\/p>\n Testiamo la funzione, se tutto \u00e8 stato impostato correttamente il test dovrebbe riuscire con un output simile a quello seguente:<\/span><\/p>\n {<\/span> Una volta pronta la funzione possiamo effettuare il provisioning delle altre risorse<\/strong>.<\/span><\/p>\n All\u2019applicazione occorrer\u00e0 un ulteriore bucket S3 per gli upload dei file degli utenti. Anche in questo caso si tratter\u00e0 di un bucket privato. Provvediamo quindi alla sua creazione nello stesso modo utilizzato per il front-end, e prendiamo nota del nome del bucket, ci servir\u00e0 per la configurazione dell\u2019applicazione.<\/span><\/p>\n Servir\u00e0 anche una tabella di DynamoDB<\/strong> per contenere i metadati e le informazioni di share dei file. Procediamo quindi alla creazione di una tabella lasciando i valori di default e specificando \u201cshareID\u201d come chiave di partizione primaria.<\/span><\/p>\n A questo punto dobbiamo occuparci di Cognito<\/strong> e di API Gateway<\/strong>. Il primo \u00e8 necessario per la parte di autenticazione, ed il secondo permetter\u00e0 al front-end di accedere alle funzionalit\u00e0 del back-end lambda mediante chiamate https.<\/span><\/p>\n Per prima cosa creiamo e configuriamo una Cognito User Pool<\/strong>.<\/span><\/p>\n Durante il Wizard di creazione possiamo personalizzare alcuni comportamenti; per far funzionare l\u2019applicazione bisogna creare un Pool che permetta gli utenti di registrarsi mediante email e di verificare l\u2019indirizzo utilizzando un codice di sicurezza gestito da Cognito. Occorre anche creare un\u2019app client e prendere nota del suo ID.<\/span><\/p>\n Scegliamo un nome per la User Pool e avviamo il wizard<\/span><\/p>\n Configuriamo il meccanismo di autenticazione e i campi del profilo.<\/span><\/p>\n Infine bisogna creare un app client e prendere nota del suo ID. Non bisogna far generare alcun segreto, non servir\u00e0 per l\u2019utilizzo di Cognito mediante web app.<\/span><\/p>\n Con Cognito abbiamo finito per ora, queste risorse saranno utilizzate dall\u2019applicazione e da API Gateway per il meccanismo di autenticazione.<\/span><\/p>\n Infine procediamo alla creazione di una API su API Gateway.<\/span><\/p>\n Questo componente fa da interfaccia tra le richieste dell\u2019utente e la funzione lambda, inoltre si occuper\u00e0 in modo automatico dell\u2019autenticazione delle richieste mediante la user pool di Cognito. <\/span><\/p>\n Per scopo di test procediamo alla creazione di una API semplice con soltanto un metodo GET che chiama la funzione lambda.<\/span><\/p>\n Una volta configurata l\u2019integrazione \u00e8 possibile testarla<\/span><\/p>\n Nell\u2019ultimo articolo della serie ci occuperemo della parte applicativa<\/strong> e della pipeline di CD\/CI<\/strong>, e vedremo come integrare Cognito in API Gateway<\/strong> per beneficiare dell\u2019autenticazione automatica.<\/span><\/p>\n Stay tuned! \ud83d\ude42<\/span><\/p>\n Leggi la prima parte<\/a> | Leggi la terza parte<\/a><\/p>\n","protected":false},"excerpt":{"rendered":" Leggi la prima parte | Leggi la terza parte Con la sempre maggiore diffusione dello sviluppo Serverless, \u00e8 di fondamentale […]<\/p>\n","protected":false},"author":6,"featured_media":362,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[477],"tags":[263,364,360,267],"class_list":["post-284","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud-native-development","tag-aws-lambda","tag-ci-cd","tag-continuous-delivery","tag-serverless"],"yoast_head":"\nL\u2019applicazione \u00e8 composta da un front-end<\/strong> e un back-end<\/strong><\/p>\n
front-end<\/strong><\/h3>\n
\n
back-end<\/strong><\/h3>\n
\n
PREPARAZIONE DEL FRONT-END<\/strong><\/h3>\n
<\/p>\n
<\/p>\n
<html><\/span>\r\n\u00a0 \u00a0 \u00a0 <head><\/span>\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <title><\/span>Esempio<\/span><\/title><\/span>\r\n\u00a0 \u00a0 \u00a0 <\/head><\/span>\r\n\r\n\u00a0 \u00a0 \u00a0 <body><\/span>\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<h1><\/span>It Works<\/span><\/h1><\/span>\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<hr\/><\/span>\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<p><\/span>This is a simple test page<\/span><\/p><\/span>\r\n\u00a0 \u00a0 \u00a0 <\/body><\/span>\r\n<\/html><\/span><\/pre>\n
<\/p>\n
<\/p>\n
<\/p>\n
<\/p>\n
<\/p>\n
\n<\/span>In alcuni casi, anche dopo l\u2019attivazione della distribuzione potrebbe essere visualizzato un errore di accesso, tuttavia si tratta di una situazione transitoria dovuta ai tempi di propagazione DNS, e si risolve autonomamente entro qualche minuto. [Pu\u00f2 richiedere fino ad un ora NDR]<\/span><\/p>\n<\/p>\n
PREPARAZIONE DEL BACK-END<\/strong><\/h3>\n
Ecco un esempio per restituire sempre un messaggio:<\/span><\/p>\n
def<\/b> lambda_handler<\/b>(event, context):<\/span>\r\n \u00a0\u00a0\u00a0<\/span>\r\n \u00a0\u00a0\u00a0response = {<\/span>\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span>\"statusCode\"<\/span>: <\/span>200<\/b>,<\/span>\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span>\"body\"<\/span>: <\/span>'Hello from Lambda!'<\/span>\r\n \u00a0\u00a0\u00a0}<\/span>\r\n \u00a0\u00a0\u00a0<\/span>\r\n \u00a0\u00a0\u00a0<\/span>return<\/b> response<\/span><\/pre>\n
\n<\/span> \u00a0<\/span>“statusCode”<\/span>: <\/span>200<\/b>,<\/span>
\n<\/span> \u00a0<\/span>“body”<\/span>: <\/span>“Hello from Lambda!”<\/span>
\n<\/span>}<\/span><\/p>\n<\/p>\n
<\/p>\n
<\/p>\n
<\/p>\n
<\/p>\n
<\/p>\n
<\/p>\n