{"id":98,"date":"2017-03-10T15:33:42","date_gmt":"2017-03-10T14:33:42","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=98"},"modified":"2023-02-22T17:22:28","modified_gmt":"2023-02-22T16:22:28","slug":"full-stack-continuous-delivery-su-aws","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/full-stack-continuous-delivery-su-aws\/","title":{"rendered":"Full stack Continuous Delivery su AWS"},"content":{"rendered":"
Con il lancio di CodeBuild<\/a> avvenuto lo scorso novembre sul palco del re:Invent<\/a>, AWS ha aggiunto il tassello mancante alla suite di strumenti gestione del ciclo di sviluppo del software<\/span><\/p>\n Noi c\u2019eravamo<\/a> e non aspettavamo altro per poterci mettere all\u2019opera e implementare finalmente un sistema di Continuous Delivery interamente basato su servizi gestiti da Amazon Web Services<\/strong>.<\/p>\n <\/p>\n Prima di CodeBuild, infatti, la suite di AWS copriva unicamente gli aspetti relativi al source control (CodeCommit<\/a>), alla gestione dei rilasci (CodeDeploy<\/a>) e all\u2019orchestrazione (CodePipeline<\/a>), costringendo gli sviluppatori ad utilizzare tool di terze parti (ad esempio Jenkins<\/a>) per la gestione delle fasi di build e test. Tool che vanno configurati e gestiti manualmente, con tutte le problematiche che ne conseguono in termini di complessit\u00e0, costi e affidabilit\u00e0 della soluzione.<\/span><\/p>\n Pensiamo infatti a quanto lo stack di Continuous Delivery\u00a0da un lato sia critico (un inconveniente a questi tool pu\u00f2 compromettere ore o giorni di lavoro di un intero team di sviluppo), ma dall\u2019altro rappresenti, specie per team DevOps piccoli e agili, un oggetto estraneo alle attivit\u00e0 \u201ccore\u201d, su cui concentrare il minor sforzo possibile; una sorta di <\/strong><\/span>black-box<\/i> che deve semplicemente funzionare. <\/strong><\/p>\n Uno stack di Continuous Delivery deve:<\/span><\/p>\n Per gli utenti AWS, l\u2019utilizzo di uno stack di CD interamente basato sui suoi servizi managed \u00e8 il modo pi\u00f9 naturale ed immediato di rispondere a tutti questi requisiti<\/span><\/p>\n Rivediamo brevemente quali sono i tool che abbiamo a disposizione:<\/span><\/p>\n Il nostro team ha realizzato una soluzione completa e automatizzata per la gestione del software lifecycle su Amazon Web Services<\/strong>, applicabile sia su ambienti ibridi (in questo caso l\u2019integrazione con il repository e la build avviene in Cloud, mentre il deploy pu\u00f2 svolgersi su qualsiasi tipo di istanza, sia in Cloud che on-premise), che su ambienti interamente Cloud-based, con le macchine di staging e produzione anch\u2019esse sul Cloud.<\/span><\/p>\n <\/p>\n Utilizzare solo servizi AWS, compatibili e progettati appositamente per cooperare tra di loro, ha il vantaggio di poter disporre di trigger specifici e setup estremamente semplificati. Tutto scala automaticamente e senza la necessit\u00e0 di interventi tecnici particolari<\/strong>; il team \u00e8 quindi sollevato dall\u2019onere di dimensionare a priori l\u2019infrastruttura di Continuous Delivery.<\/p>\n E\u2019 possibile, inoltre, gestire la security e i permessi in modo granulare sfruttando IAM role e IAM policy. A differenza di ci\u00f2 che avviene con l\u2019utilizzo di altri strumenti poi, \u00e8 possibile rimanere confinati all\u2019interno della sandbox di un singolo account Amazon, senza dover esporre nessun endpoint all\u2019esterno per avviare il processo di build.<\/span><\/p>\n Abbiamo scoperto\u00a0che CodeBuild si occupa delle fasi di build e test sfruttando il provisioning dei container; questi ultimi si avviano solo quando necessario, ottimizzando cos\u00ec le prestazioni ed eliminando la necessit\u00e0 di istanze dedicate come avviene ad esempio durante l\u2019utilizzo di Jenkins.<\/span><\/p>\n Altra caratteristica fondamentale di CodeBuild \u00e8 l\u2019isolamento, che permette di segregare ogni build sia a livello applicativo, sia a livello delle release.<\/strong><\/span><\/p>\n Prima di cominciare col tutorial, buttiamo un occhio ai costi AWS generati da questa soluzione:<\/span><\/p>\n Il prezzo di ciascuna pipeline di CodePipeline \u00e8 di 1$\/mese, mentre, per i primi 5 utenti (50GB e 10000 richieste git), il servizio CodeCommit \u00e8 totalmente gratuito. Dal sesto utente in avanti il costo \u00e8 di 1$\/mese a utente.<\/span><\/p>\n Il costo del servizio CodeBuild \u00e8 calcolato in base ai minuti di utilizzo effettivo dei container che effettuano le build, modello che permette un notevole risparmio economico rispetto ai classici runner basati su istanze EC2, che sono invece tariffate su base oraria <\/span><\/p>\n CodeDeploy \u00e8 gratuito, senza limiti di traffico o di tempo.<\/span><\/p>\n A questi vanno aggiunti i costi di storage e banda generati da S3, che viene utilizzato come storage di appoggio degli artifact tra uno step e l\u2019altro di ogni pipeline.<\/span><\/p>\n Ovviamente i costi possono variare molto in base al contesto e all\u2019organizzazione di ogni team, ma ci sentiamo di dire che nella maggioranza dei casi questo stack risulti una delle soluzioni pi\u00f9 economiche in assoluto.<\/strong><\/span><\/p>\n Entriamo ora nel vivo dell\u2019implementazione<\/span> .<\/span><\/p>\n Il primo servizio da configurare \u00e8 CodeCommit. <\/span><\/p>\n Creiamo il repository<\/span> accedendo alla console AWS oppure, nel caso di accesso programmatico, alla CLI.<\/span><\/p>\n Creiamo ora un IAM user<\/span> che ci permetta di procedere con le principali azioni git sul repository appena creato. <\/span><\/p>\n A ogni\u00a0push del codice sorgente dell\u2019app, questo viene preso in carico da CodeBuild, che si occupa del provisioning di un ambiente temporaneo e isolato (container) all\u2019interno del quale si svolgeranno le fasi di build e test.<\/span><\/p>\n Prima di procedere alle fasi di test e build, configuriamo CodeBuild specificando il taglio del container<\/span>, il tipo di immagine desiderata<\/span> (ad esempio container Linux con preinstallato un framework fra quelli disponibili o un\u2019immagine custom) e specificando i passaggi<\/span> che desideriamo che CodeBuild svolga per effettuare test e build dell\u2019app. Quest\u2019ultimo passaggio prevede la scelta tra due metodologie<\/span>: dichiarazione dei comandi inline oppure mediante un file denominato buildspec.yml che andr\u00e0 a richiamare gli hook del ciclo di build. <\/span><\/p>\n Noi abbiamo scelto di utilizzare quest\u2019ultimo metodo poich\u00e9, in questo modo, il file YAML buildspec pu\u00f2 essere versionato insieme al codice dell\u2019applicazione<\/span>, dandoci la possibilit\u00e0 di cambiare le procedure di test e build appena prima della fase di build stessa.<\/span><\/p>\n All\u2019interno di ciascun hook, quindi, abbiamo specificato i comandi che CodeBuild dovr\u00e0 eseguire, momento per momento.<\/span><\/p>\n Di seguito un esempio generico della struttura di un file buildspec.yml posto nella root directory del repository: \u00a0<\/span><\/p>\n Dall\u2019ultima fase del buildspec.yml abbiamo fatto in modo di ottenere un bundle che fosse compatibile con CodeDeploy, servizio utilizzato nella prossima fase; il pacchetto ottenuto dall\u2019ultima fase di build contiene sia l\u2019applicazione pronta per essere messa in opera, sia gli script da eseguire per installarla e configurarla sull\u2019istanza di deploy<\/span>.<\/span><\/p>\n Il funzionamento di CodeDeploy prevede l\u2019esecuzione dei propri script dall\u2019interno dell\u2019istanza; per questo, su ogni istanza dell\u2019infrastruttura target del processo, andranno installati la CLI di AWS e il CodeDeploy agent. <\/span><\/p>\n Creiamo\u00a0un file contenente la dichiarazione degli hook, questa volta denominato appspec.yml. Dopo aver creato da zero gli script necessari, abbiamo deciso, per ciascun hook, quali e quanti di essi chiamare.<\/span><\/p>\n Il file YAML appspec, in questo specifico caso, prevede che nel bundle vengano create due cartelle: una (<\/span>App) <\/span><\/i>dedicata all\u2019applicazione e una (<\/span>Scripts)<\/span><\/i> dedicata agli script. <\/span><\/p>\n Di seguito un esempio generico della struttura di un file appspec.yml posto nella root directory del bundle: \u00a0<\/span><\/p>\n Parallelamente ai tre tool che abbiamo appena descritto, lavora CodePipeline, l\u2019ochestrator dei servizi che si occupa di passare gli output generati da ciascuna fase al servizio successivo che li utilizzer\u00e0 come input per svolgere il proprio compito.<\/span> Ogni fase del processo di Continuous Integration sfrutta la piattaforma S3 come storage di supporto.<\/p>\n Affinch\u00e9 CodePipeline funzioni, occorre creare una pipeline<\/span>; per fare ci\u00f2, accediamo alla console AWS ed effettuiamo i seguenti passaggi:<\/span><\/p>\n La Pipeline \u00e8 stata creata con successo.<\/span><\/p>\n Nel momento in cui CodeCommit viene collegato a CodePipeline si crea automaticamente un trigger che fa corrispondere ad ogni <\/span><\/span>git push<\/span><\/i><\/span> effettuato l\u2019avvio del processo descritto nella pipeline creata<\/span>.<\/span><\/p>\n Il codice sorgente risultato da questa fase viene consegnato, sotto forma di input, a CodeBuild, il quale genera un bundle che servir\u00e0 a sua volta da input a CodeDeploy. Sar\u00e0 quest\u2019ultimo ad installare l\u2019app sull\u2019infrastruttura target.<\/span><\/p>\n N.B. \u00e8 importante verificare la correttezza del codice generato alla fine di ciascuna fase da ciascuno strumento; essendo ciascun risultato il punto di partenza per la fase successiva, se un output risultasse sbagliato, tutto il processo di deploy risulterebbe compromesso.<\/span><\/i><\/p><\/blockquote>\n Noi stiamo utilizzando questa soluzione da ormai qualche settimana e siamo estremamente soddisfatti: abbiamo eliminato\u00a0tutti gli effort di gestione della nostra precedente infrastruttura di Continuous Delivery, aumentando il numero di build che possiamo gestire in parallelo, e stiamo anche spendendo sensibilmente meno<\/span>. Questo stack si rivela quindi ottimo in termini di efficienza, affidabilit\u00e0 ed economicit\u00e0. <\/span><\/p>\n E voi, cosa ne pensate? <\/span><\/p>\n Se la nostra soluzione vi ha incuriositi e l\u2019idea di implementarla nel vostro flusso di lavoro vi esalta, lasciate un commento o\u00a0contattateci<\/a>! Saremo felici di rispondere ad ogni vostra domanda, di leggere le vostre impressioni e, perch\u00e9 no, di aiutarvi a trarre il massimo vantaggio da questa applicazione.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":" Con il lancio di CodeBuild avvenuto lo scorso novembre sul palco del re:Invent, AWS ha aggiunto il tassello mancante alla […]<\/p>\n","protected":false},"author":3,"featured_media":108,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[241],"tags":[364,360],"class_list":["post-98","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-ci-cd","tag-continuous-delivery"],"yoast_head":"\n\n
La soluzione<\/h2>\n
\n
I Costi AWS<\/h2>\n
CodeCommit<\/h2>\n
<\/p>\n
\n<\/span>Per ottenere i permessi di accesso al repo, occorre autenticarsi come IAM user. Ecco i possibili metodi:<\/span><\/p>\n\n
CodeBuild<\/h2>\n
<\/p>\n
version: 0.1\r\n\r\nenvironment_variables:\r\nplaintext:\r\nJAVA_HOME: \"\/usr\/lib\/jvm\/java-8-openjdk-amd64\"\r\n\r\nphases:\r\ninstall:\r\ncommands:\r\n- apt-get update -y\r\n- apt-get install -y maven\r\npre_build:\r\ncommands:\r\n- echo Nothing to do in the pre_build phase...\r\nbuild:\r\ncommands:\r\n- echo Build started on `date`\r\n- mvn install\r\npost_build:\r\ncommands:\r\n- echo Build completed on `date`\r\nartifacts:\r\nfiles:\r\n- target\/messageUtil-1.0.jar\r\ndiscard-paths: yes\r\n<\/pre>\n
CodeDeploy<\/h2>\n
<\/p>\n
version: 0.0\r\nos: linux\r\nfiles:\r\n- source: App\/\r\ndestination: \/var\/www\/html\/\r\n- source: nginx.conf\r\ndestination: \/etc\/nginx\/\r\nhooks:\r\nBeforeInstall:\r\n- location: Scripts\/UnzipResourceBundle.sh\r\ntimeout: 300\r\nrunas: root\r\n- location: Scripts\/InstallDependencies.sh\r\ntimeout: 300\r\nrunas: ubuntu\r\nAfterInstall:\r\n- location: Scripts\/FixPermissions.sh\r\ntimeout: 300\r\nrunas: root\r\nApplicationStart:\r\n- location: Scripts\/WebServerStart.sh\r\ntimeout: 300\r\nrunas: root\r\nValidateService:\r\n- location: Scripts\/ValidateService.sh\r\ntimeout: 300\r\nrunas: ubuntu<\/pre>\n
CodePipeline<\/h2>\n
\n
<\/p>\n
\n
<\/p>\n
\n
<\/p>\n
\n
<\/p>\n
<\/p>\n