Tag Archivio per: Terraform

Un esempio di progetto di Cloud Development Kit (CDK) in TypeScript, che permetta di creare un’infrastruttura completa di Network, EC2, RDS, CloudFront, backup e monitoring.

Come discusso nell’articolo precedente “INFRASTRUCTURE AS CODE (IAC): COS’È?”, Cloud Development Kit è una delle scelte tecnologiche possibili quando si decide di utilizzare un approccio di Infrastructure As Code per una infrastruttura AWS.

In questo caso approfondiremo un esempio di progetto, che permetta di realizzare una infrastruttura completa e pronta all’uso.
Presupponendo che l’utente abbia configurato il proprio PC con le proprie credenziali AWS, si può installare prima NodeJS e poi CDK tramite pacchetto npm.
Se dovessero servire indicazioni aggiuntive, si può fare riferimento alla documentazione ufficiale: https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html.

Per ricevere il codice realizzato per questo articolo compilando il form a questo link, oppure puoi partire da una cartella vuota e seguire passo passo per ottenere un progetto completo.

Come creare il progetto

Partendo da zero, create una nuova cartella e datele un nome a vostro piacimento.
Cloud Development Kit permette di sviluppare con vari linguaggi, in questo caso useremo TypeScript, quindi all’interno della cartella aprite un terminale e lanciate il seguente comando: cdk init app –language typescript per inizializzare il progetto.

A questo punto avrete una cartella popolata con vari file, nella root ad esempio troviamo i comuni README.md e package.json tipici di un progetto NodeJS, ma anche un particolare file cdk.json che vedremo tra poco.

In questo articolo ci concentreremo in particolare sulle cartelle “bin” e “lib” in quanto qui andremo a definire i servizi AWS che vogliamo creare.
Non tratteremo l’argomento dei test in questo articolo, quindi ci concentreremo sulle attività di codifica e deploy dell’infrastruttura.
Partendo dal file “cdk.json”, qui il campo di interesse è il cosiddetto “context”. Al suo interno definiamo un contesto per ogni ambiente in cui vogliamo effettuare un deploy, nel nostro caso li abbiamo chiamati “dev” e “prod”. Qui definiamo quante più variabili ci possono servire, tenendo conto che se rendiamo il file troppo complesso, risulterà anche più difficile da leggere e da mantenere.

Definizione della struttura

Abbiamo individuato come buona prassi, quella di definire una struttura come la seguente, andando poi a personalizzare l’oggetto “stacks” in base alle necessità:

Nella cartella “bin” troviamo un unico file, che è l’entry point del progetto. Il nome del vostro file dipenderà dal nome della cartella dentro la quale avete eseguito il comando di init in precedenza. Di seguito uno snippet del file, senza gli import dei vari pacchetti, e con la definizione di un solo stack, per brevità.

 

Dato che ogni costrutto CDK deve essere istanziato in un determinato scope, qui troviamo l’inizializzazione di un oggettoApp” che farà da contenitore di tutti gli stack che andremo ad istanziare. I vari servizi che andremo a definire, invece, saranno realizzati nello scope del rispettivo stack di appartenenza.

Successivamente definiamo un oggetto “builConfig”, che contiene tutte le variabili d’ambiente del deploy che vogliamo eseguire. Il tipo di oggetto “BuildConfig” è definito nel file “/lib/common/build-config.ts”. In pratica è un’interfaccia che corrisponde 1:1 ai campi presenti nell’oggetto context del file “cdk.json”. In questo modo la costante “buildConfig” conterrà tutte le variabili d’ambiente del deploy che stiamo effettuando, e le avremo disponibili negli stack in cui passiamo tale oggetto.

Creiamo anche la costante “envDetails” che viene passata ad ogni stack istanziato, per fornire le informazioni su che account e regione AWS tale stack sarà creato.

La costante “prefix” invece è una pura comodità per facilitare la nomenclatura delle risorse, in modo da avere uno standard unico in tutto il progetto.

Arrivando alla dichiarazione dello stack, così come per i costrutti che rappresentano i servizi, il costruttore si aspetta:

  • scope: che come detto per gli stack è l’App;
  • id: un identificativo derivante dalla dipendenza da CloudFormation, che serve a garantire l’unicità della risorsa durante il deploy;
  • proprietà: queste dipendono in numero e tipo da come abbiamo definito lo stack, quindi in questo caso ad esempio viene passato l’oggetto “buildConfig”, ma potremmo passare anche interi stack ad altri stack, creando così delle dipendenze;

Infine definiamo la funzione “addTagsToStack()” che serve per aggiungere dei tag allo stack CloudFormation che verrà creato. Dato che i costrutti che gli appartengono ereditano tali tag, ci troveremo anche i servizi creati taggati in questo modo e ciò faciliterà la manutenzione dell’infrastruttura e l’individuazione delle risorse create con IaC oppure no. Ovviamente tali tag possono essere aggiunti e modificati in base alle necessità.

Passiamo ora alla cartella “lib”, che contiene tutte le dichiarazioni degli stack. Queste seguono la seguente struttura:

 

Ogni stack è una classe TypeScript che estendiamo per definire le proprietà di interesse. Tutte le proprietà che vogliamo esporre agli stack che importeranno questo stesso stack, le dichiariamo come “public” e saranno accessibili come campi dell’oggetto, quindi ad esempio “networkStack.vpc” oppure “networkStack.privateSubnets”.

Le definizioni di questi campi, e tutti i servizi che appartengono a questo stack, li gestiamo all’interno del costruttore.

Partendo in ordine alfabetico, vediamo i file della cartella “lib”.

La documentazione dei costrutti è disponibile al link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html. Unico appunto, nel caso si arrivi alla documentazione tramite link esterni (esempio Stack Overflow), fare attenzione a controllare di essere nella versione #2 di CDK, visto che è la più aggiornata.

 

Backup

Qui creiamo una chiave KMS per criptare i backup, decidendo la “retentionPolicy” in base all’ambiente in cui siamo. La chiave poi la passiamo alla vault che andiamo a creare, che sarà il raccoglitore dei backup.
La frequenza con cui vengono realizzati i backup deriva dalle regole del piano.

Nell’esempio prevediamo una regola giornaliera con retention 7 giorni, una regola settimanale con retention 3 settimane, ed una regola mensile con retention 3 mesi.

La selezione di quali risorse sono comprese in questo piano, avviene tramite tag, in particolare, se ipotizziamo di essere in ambiente “dev”, il tag che verrà considerato valido in questo caso sarà con chiave “aws-backup-active-dev” e valore “true”.

 

CloudFront

Qui creiamo un bucket S3 che useremo per salvare i file ad esempio di una Single Page Application (che potrebbe essere realizzata in Angular) che verrà distribuita dalla distribuzione CloudFront. In particolare il bucket sarà privato, ed i contenuti saranno accessibili dal web solo tramite la CDN, ciò è reso possibile definendo il “defaultRootObject” che cerca un file “index.html” nella root del bucket.

Per rendere il sito più sicuro agganciamo un WAF, il servizio di firewall di AWS, che essendo un servizio globale sarà deployato sulla regione Nord Virginia. Per recuperare l’arn in maniera automatica, utilizziamo l’oggetto “parameterReader” definito nella cartella “common” che eseguirà una chiamata API.

 

EC2

In questo progetto di esempio, il servizio EC2 lo utilizziamo solo per la creazione di un’istanza ponte per poterci collegare alle risorse che saranno in sottoreti private, in particolare il database RDS. Nel costrutto EC2 decidiamo il tipo di istanza da utilizzare, l’AMI (quindi il sistema operativo), la quantità di storage, la posizione nella rete VPC, ed il security group che definisce le regole di accesso a questa istanza.

Come accortezza, verificare che l’AMI scelta sia disponibile nella regione di deploy, e che la chiave PEM sia già stata creata sulla console AWS. Per comodità successivamente agganciamo un Elastic IP per avere un IP pubblico statico a cui connettersi.

 

ECS

Questo è probabilmente il file che contiene più definizioni di risorse.

Nella prima parte definiamo il bilanciatore come pubblico, e creiamo un listener HTTPS su porta 443. Il listener è unico perché i target group sono differenziati tramite “host-header” nelle regole del listener. Il traffico sarà quindi in HTTPS dal bilanciatore verso internet, mentre in HTTP dal bilanciatore verso i servizi ECS.

 

Nella seconda parte andiamo a definire il cluster ECS con i rispettivi servizi e task.

Per facilitare la configurazione, cicliamo sugli oggetti “buildConfig.stacks.ecs.services“ definiti in “cdk.json”. Questo è uno dei vantaggi maggiori di un approccio IaC, in quanto con un minimo sforzo, possiamo replicare la configurazione per tutti i servizi eliminando gli errori umani che potrebbero verificarsi eseguendo le operazioni da console o definendole una ad una. Per ogni servizio ECS è previsto un Log Group, un repository ECR ed il proprio Task Definition.

Come detto, le configurazioni principali vengono prese dal “cdk.json” quindi non è necessario modificare il codice a meno di cambiamenti strutturali.

 

Network

Lo stack Network prevede la creazione della rete VPC, ed all’interno due sottoreti private e due pubbliche. I range di IP e l’AZ da utilizzare sono definiti sul “cdk.json” quindi anche qui si può evitare di modificare il codice, trovandosi tutte le risorse nominate correttamente in base alle configurazioni.

 

RDS

Per il database il costrutto dipende dal tipo di engine scelto (esempio MySQL o PostgreSQL) e dalla scelta tra istanza RDS o cluster Aurora, quindi alcune modifiche lato codice sono possibili se si vogliono cambiare queste configurazioni. In questo caso creiamo un’istanza singola di RDS MySQL, con autoscaling dello storage definito tramite parametri del “cdk.json”. Da notare come vengono disabilitati i backup automatici di RDS impostando “backupRetention: Duration.days(0)” perché aggiungiamo il tag apposito che abbiamo previsto per la selezione di AWS Backup, in modo da non avere un costo doppio per lo storage dei backup stessi.

 

Security

Per abitudine raccogliamo le definizioni dei Security Group in un unico stack, per prevenire dipendenze circolari nel codice. Infatti è buona prassi utilizzare nelle regole gli ID dei Security Group dei servizi da cui vogliamo abilitare le connessioni, ed è quindi più comodo e semplice da mantenerli configurarli in un unico file.

Qui ad esempio abilitiamo le richieste verso il DB solo dai servizi ECS e dall’istanza EC2 ponte.

 

WAF

Il Web Application Firewall è un servizio che può essere agganciato sia a CloudFront che ad un Application Load Balancer, in base a se viene deployato a livello globale o sulla regione dell’ALB. Viene previsto un IP set per avere delle sorgenti in whitelist, e poi delle regole gestite da AWS che coprono casi d’uso tipici come, ad esempio, un attacco di SQL Injection.

Viene salvato un parametro su SSM con l’arn del WAF appena creato, che verrà poi richiamato dalla funzione “parameterReader” nel modulo di CloudFront descritto in precedenza.

Essendo da deployare a livello globale, lo stack dedicato al WAF dovrà essere in Nord Virginia, quindi c’è da fare attenzione ad eseguire il bootstrap di CDK anche in tale regione.

Arrivati al momento del deploy, vengono previsti degli script npm che facilitano l’operazione in modo da non dover ricordare la sintassi completa:

  • “cdk-diff-dev”: “cdk context –clear && cdk diff $npm_config_stack -c config=dev –profile PROFILE_NAME”,
  • “cdk-deploy-dev”: “cdk context –clear && cdk deploy $npm_config_stack -c config=dev –profile PROFILE_NAME”,
  • “cdk-destroy-dev”: “cdk destroy $npm_config_stack -c config=dev –profile PROFILE_NAME”,

Quindi ad esempio per eseguire il deploy di un singolo stack  in ambiente dev il comando da eseguire sarebbe: “npm run cdk-deploy-dev –stack STACK_NAME”.

Prendendo come esempio lo stack “ec2” che ha come parametri del costruttore anche gli stack “network” e “security”, CDK vedrà la dipendenza e li eseguirà prima dello stack “ec2” in modo da trovare pronti tutti i parametri necessari.

 

I principali vantaggi

Come avete potuto capire dall’esempio precedente un approccio di gestione architetturale tramite Infrastructure As Code permette di creare, controllare, aggiornare e gestire via codice un’infrastruttura rendendo programmabile quello che tipicamente veniva svolto manualmente. Alcuni dei numerosi vantaggi derivanti sono:

  • Flessibilità
  • Chiarezza sulle operazioni svolte
  • Maggiore controllo
  • Sicurezza
  • Replicabilità
  • Riduzione degli errori
  • Documentazione sempre aggiornata

Tutto ciò però è possibile con competenze trasversali che vanno da aspetti sistemistici e infrastrutturali fino allo sviluppo software che, grazie all’approccio IaC, sarà sempre più integrato con gli applicativi sviluppati.

Per riuscire a trarne il massimo vantaggio, le organizzazioni devono iniziare a pensare alla gestione dei sistemi informativi come servizi in continua evoluzione e creare team estesi composti da tecnici, persone di business interne e partner in grado di evolvere e seguire il mercato con la stessa velocità dell’evoluzione tecnologica spinta ancora di più dai servizi cloud.

Se vuoi condividere la tua esperienza su questo ambito e le tue opinioni usa la funzione commenti!

Questo è il secondo articolo della serie a cui stiamo lavorando per trattare vari argomenti legati al mondo AWS ed in particolare sugli approcci di Infrastructure As Code.

Contattateci all’indirizzo hello@zero12.it, per richiedere degli articoli o per chiederci di trattare argomenti specifici… oppure seguite i nostri canali social per restare informati sulle prossime pubblicazioni.

Ciao 🙂

Alessandro Dindinelli

AWS Specialist zero12 – Var Group Company

 

 

Infrastructure as Code (IaC)

Infrastructure as Code (IaC): concetti base, confronto tra le tecnologie più usate (CloudFormation, CDK e Terraform) e i motivi per cui un’azienda dovrebbe scegliere questo approccio per lo sviluppo e la manutenzione della propria infrastruttura su AWS.

 

Prima di approfondire l’Infrastructure as Code (IaC) è importante sottolineare che quando un’azienda si approccia al voler utilizzare l’infrastruttura AWS, gli scenari più comuni sono principalmente due:

  • 1. l’azienda potrebbe voler migrare interamente o parte dei propri servizi esistenti gestiti in quel momento on premise;
  • 2. l’azienda preferisce partire da zero con un nuovo progetto direttamente sul Cloud.

Possono sembrare casi completamente diversi, ma in entrambi ci sono spesso valide ragioni per le quali l’azienda potrebbe avere la necessità di terminare la propria transizione in tempi stretti: un contratto in scadenza presso il datacenter attuale, dei limiti tecnici dell’infrastruttura on premise che non permettono all’azienda di operare pienamente, una startup che ha bisogno di lanciare il proprio prodotto per potersi rendere fruibile dai propri clienti e molto altro.

IaC: come individuare l’approccio migliore

Spesso si rischia di farsi prendere dalla fretta e scegliere un approccio manuale che può sembrare inizialmente più semplice e veloce. Il problema di questo approccio è la facilità con cui si può perdere traccia delle modifiche fatte in fase di configurazione e fine tuning. Questo può comportare varie problematiche. Nel breve periodo, ad esempio, il non riuscire a replicare interamente l’ambiente di test su quello di produzione ritrovandosi problemi inaspettati a ridosso delle scadenze di go-live/migrazione. Oppure a lungo andare la difficoltà di manutenzione dell’infrastruttura in quanto il personale tecnico, potenzialmente diverso nel tempo, non avrà tutte le indicazioni necessarie per poter operare.

Per ridurre e/o risolvere queste problematiche l’approccio migliore è definire dei template di codice per la propria infrastruttura, tramite tecnologie come AWS CloudFormation, AWS CDK (Cloud Development Kit) e Terraform.
Con l’Infrastructure As Code (IaC) quindi intendiamo la definizione dell’infrastruttura tramite dei file con linguaggi e sintassi specifici che permettono un approccio programmatico alla gestione dei servizi Cloud.
Sono tecnologie diverse tra loro e non è oggetto di questa discussione andarle ad approfondire tutte, ma è utile vedere brevemente le loro caratteristiche principali.

AWS CloudFormation

CloudFormation è a tutti gli effetti un servizio AWS, ed il primo riguardo IaC in linea temporale, e può quindi essere visitato sulla console. Il funzionamento si basa sulla definizione di file scritti in linguaggio JSON o YAML con una sintassi ben precisa, che vengono poi caricati manualmente sulla console oppure automaticamente tramite delle pipeline apposite di CI/CD (Continuous Integration e Continuous Delivery). Di seguito un esempio di istanza EC2 in CloudFormation, utilizzando il linguaggio YAML. I campi dati inseriti sono stringhe, oppure riferimenti a variabili dichiarate precedentemente e la formattazione ha una struttura molto rigida.

un esempio di istanza EC2 in CloudFormation, utilizzando il linguaggio YAML

AWS Cloud Development Kit (CDK)

AWS CDK è un sistema di templetizzazione costruito ad un livello più alto di CloudFormation e che permette l’utilizzo dei linguaggi di programmazione più diffusi tra gli sviluppatori come Javascript, Typescript, Python, Go, Java ed altri ancora.
Un progetto CDK ha una struttura ben definita, che facilita la suddivisione dell’infrastruttura in più aree di interesse. Di seguito un esempio di istanza EC2 in CDK, utilizzando il linguaggio TypeScript. Le variabili possono essere di qualsiasi tipo permesso dal linguaggio, oppure provenire da stack differenti che sono stati importati.

un esempio di istanza EC2 in CDK, utilizzando il linguaggio TypeScript

Terraform

Terraform è un progetto open source, inizialmente sviluppato da HashiCorp.
É una tecnologia molto matura, che permette la definizione delle risorse infrastrutturali tramite un linguaggio di programmazione appositamente sviluppato chiamato HCL (HashiCorp Configuration Language) con una struttura simile al JSON, che è agnostico rispetto al Cloud Provider scelto. Di seguito un esempio di istanza EC2 in Terraform, utilizzando il linguaggio HCL. Anche qui le variabili possono essere dichiarate in altri moduli o parti del codice e poi importate.

un esempio di istanza EC2 in Terraform, utilizzando il linguaggio HCL

Costi

Riguardo l’argomento costi questi approcci non comportano una spesa diretta, nel senso che non si pagano le operazioni di deploy, ma richiedono chiaramente di pagare per le risorse che verranno create tramite i template IaC secondo le tariffe standard di quei servizi espresse da AWS.

I vantaggi dell’approccio IaC

Qualunque sia la tecnologia scelta si potranno ottenere dei template uniformi, replicabili, versionati e testabili. Tutti gli approcci permettono il riuso del codice, così che si possa anche risparmiare tempo per non dover reinventare la ruota ed usare componenti magari provenienti da altri progetti precedenti dell’azienda, ma che con poche modifiche possono essere adattati, riducendo ampiamente i tempi di sviluppo e gli errori umani.
Ad esempio questo significa che se in un progetto l’ambiente di test è stato ben definito e templetizzato si può passare al rilascio e quindi alla creazione dell’ambiente di produzione in rapidità, con la sicurezza che le configurazioni codificate verranno replicate sul nuovo ambiente.

Precisiamo che con il termine ambiente possiamo intendere sia un’infrastruttura che contiene tutte le risorse in un unico account, sia un progetto che è diviso su più account AWS. Il valore aggiunto della replicazione delle configurazioni che viene dato dall’utilizzo dell’approccio IaC persiste, in quanto semplicemente il template IaC verrà configurato con tutti gli account sui quali dovrà essere rilasciato.

Problematiche dell’approccio IaC

Ovviamente il rilascio di un progetto è solo l’inizio del suo percorso. La manutenzione dell’infrastruttura è spesso dove l’approccio manuale inizia a mostrare i propri difetti in quanto diventa sempre più difficile applicare le modifiche che si rendono necessarie nel tempo. I motivi possono essere i più disparati: dal cambio di personale tecnico che si occupa del progetto alla scarsa documentazione realizzata per tenere traccia delle modifiche fatte manualmente, o magari più semplicemente, una mancanza di competenze approfondite.

Ci possono comunque essere delle problematiche nello scegliere di utilizzare un approccio Infrastructure as Code (IaC). In primo luogo la dipendenza dal codice, che comporta la necessità di avere almeno una figura di riferimento all’interno dell’azienda con le competenze per poter operare le modifiche sul template che si renderanno necessarie nel tempo.
Come secondo aspetto è bene tenere a mente che ci sarà una porzione di tempo iniziale in cui lo sviluppo potrebbe essere più lento rispetto ad un approccio manuale, in quanto il personale dovrà acquisire le competenze necessarie e tracciare le configurazioni che dovranno essere templetizzate.

Quando pensiamo a tutti gli steps necessari al rilascio di un’applicazione, essere in grado di operare con rapidità ed automazioni è la chiave per garantire un rilascio veloce e di successo. La stessa mentalità deve essere applicata all’infrastruttura che sorregge tale applicazione, in quanto è chiaramente una parte fondamentale che però spesso si tende a vedere più distaccata ed in sottofondo.

Vale la pena affrontare i punti critici di un approccio IaC in quanto i benefici sono decisamente maggiori: la possibilità di versionamento dei template infrastrutturali, il poter collaborare e riusare il codice prodotto con i comuni strumenti usati dagli sviluppatori, automatizzare task complessi riducendo gli errori umani, e facilitare la manutenzione e gli aggiornamenti dei vari ambienti in uso.

IaC: trend di crescita

Dati i trend di crescita del Cloud, in futuro possiamo aspettarci che gli strumenti di IaC assumeranno sempre più importanza, sia per ambienti puramente Cloud, sia per soluzioni ibride in cui le aziende vogliono integrare la propria infrastruttura privata con il provider scelto.
Che si tratti di una multinazionale oppure di una startup, ogni azienda che ha intenzione di spostare la propria infrastruttura sul Cloud ha la possibilità di beneficiare enormemente dall’utilizzo di un approccio IaC.

Non perdere i prossimi articoli dove parleremo degli approcci dell’Infrastructure as Code (IaC) con riferimento al mondo AWS.

Per ricevere aggiornamenti su questi temi contattateci all’indirizzo hello@zero12.it, oppure seguite i nostri canali social per restare informati sulle prossime pubblicazioni!

Ciao 🙂

 

Se vuoi approfondire il Cloud Development Kit attraverso un esempio pratico clicca qui per leggere l’articolo

Alessandro Dindinelli

AWS Specialist zero12 – Var Group Company