Immutable Infrastructure: come gestire in modo sano i server in cloud

Per sfruttare al meglio le potenzialità del cloud AWS è necessario adottare alcune pratiche nella creazione e sviluppo di applicazioni e infrastruttura: in questo articolo farò una panoramica di un approccio alla progettazione dell’infrastruttura e alla configurazione dell’ambiente di esecuzione dell’applicazione noto come Immutable Infrastructure.

I ragionamenti alla base di questo approccio sono gli stessi di tecnologie come Docker e i vari orchestratori di container. Qui vedremo come applicare le stesse logiche nel mondo delle macchine virtuali, approccio molto utile, ad esempio, nella migrazione di applicativi legacy su cloud, adottando la strategia di migrazione detta Replatform.

Snowflake servers vs Phoenix servers vs Immutable servers

Una volta eravamo abituati ad installare e configurare i server a mano ed ogni server era da considerarsi un oggetto unico. Benché l’installazione iniziale potesse essere automatizzata mediante script, non era una prassi comune e in ogni caso segnava soltanto il punto di partenza del server. In seguito, i cambiamenti manuali alla configurazione dei vari server li facevano diventare unici, come dei fiocchi di neve: da queste considerazioni arriviamo appunto a definire tutti i server configurati manualmente come degli Snowflake server. Qui trovi alcuni tra i problemi principali in cui si incorre nel mantenerli:

  • Sono difficili da riprodurre.
  • Sono difficili da aggiornare senza effetti collaterali.
  • La conoscenza su cosa c’è installato e perché risiede solo nel server stesso.
  • Se gestisci un cluster di Snowflake server, mantenere la configurazione in sync fra di loro non è banale.

Un modo per risolvere parte di questi problemi è quello di passare dagli Snowflake server ai Phoenix server. Sfruttando dei tool di configuration management (ad esempio Chef o Puppet) possiamo definire delle ricette di configurazione del server. Gestendo qualsiasi modifica mediante queste ricette, siamo sicuri che ad ogni server vengano applicate le giuste configurazioni e solo quelle. Inoltre è possibile terminare uno qualsiasi dei server e ricrearlo da zero applicando nuovamente la ricetta: appunto un server che può rinascere dalle ceneri. 

I Phoenix server risolvono parte dei problemi ma abbiamo ancora alcuni punti su cui dobbiamo intervenire:

  • Il tempo che passa da quando distruggo un server e lo ricreo, include anche tutto il tempo di configurazione del server stesso e potrebbero volerci decine di minuti.
  • È necessario mantenere una buona disciplina per garantire che tutte le modifiche avvengano mediante le ricette e non tramite interventi manuali spot.
  • Le ricette coprono solo una parte del server: le modifiche a parti del sistema non coperte da queste rimangono nascoste, potrebbero influenzare il comportamento e ridurre la nostra capacità di replicare la configurazione.

Dalle considerazioni precedenti è nato il paradigma degli Immutable Server. Questa tipologia di server parte dal presupposto che l’intera configurazione si fa online e da quella si crea un’immagine contenente tutto il necessario per far girare l’applicativo, applicativo compreso. In questo modo si ottengono i seguenti vantaggi:

  • L’avvio di un nuovo server identico è questione di pochi secondi, quelli che impiega il server e l’eventuale application server a partire.
  • Possiamo gestire la creazione di queste immagini mediante delle pipeline automatizzate che comprendono una fase di test e analisi di sicurezza.
  • Lo stato del server è noto ed è sempre quello descritto dalle ricette usate per creare l’immagine.
  • Rende facile l’applicazione delle moderne tecniche di deploy, come il rolling update e il Blue/Green.

In ambiente AWS questo genere di immagini vengono definite Golden AMI: il loro utilizzo porta con sé ulteriori vantaggi perché ci abilita ad utilizzare servizi come EC2 Autoscaling in modo da rendere la nostra infrastruttura elastica, ossia in grado di aumentare e diminuire il numero di server attivi in base al carico nel sistema. In aggiunta alla caratteristica principale, ci fornisce anche la possibilità di ottenere un server in grado di essere ricreato in maniera automatica in un secondo data center (availability zone) nel caso vi siano dei problemi nella prima zona. Infine permette in maniera facile di creare degli automatismi per spegnere tutti i server fuori dagli orari di ufficio per gli ambienti di sviluppo in modo da ridurre notevolmente la bolletta AWS.

Immutable Infrastructure su AWS

Avendo spiegato le motivazioni che ci hanno portato ad adottare Immutable infrastructure, possiamo entrare più nel dettaglio su quali servizi AWS possiamo usare per raggiungere questo scopo. 

Per fare questo prendiamo in considerazione un esempio di infrastruttura molto comune composta da delle istanze EC2, nel nostro caso in autoscaling, un load balancer e un database relazionale.

Questa infrastruttura, per quanto semplice, è un buon esempio di infrastruttura elastica e altamente affidabile che si può ottenere facilmente su AWS. Abbiamo come ingresso un load balancer in grado di scalare e assorbire gli attacchi DDOS distribuito su più availability zone (data center), un database relazionale in replica sincrona su più availability zone e infine il nostro applicativo ospitato su istanze EC2 che fanno parte di un Auto scaling group.

Un Auto scaling group è un servizio AWS che rappresenta un insieme di istanze EC2 identiche fra loro, ossia create a partire dalla stessa immagine (AMI). Le sue proprietà principali sono una dimensione minima, che può essere anche zero, una dimensione massima, in modo da limitare i costi, e una dimensione desiderata che rappresenta il numero di istanze che si vuole in esecuzione in questo particolare istante (vedi immagine sotto). Nella sua forma base l’autoscaling non prevede logiche che permettono lo scaling dinamico: può essere utilizzato come sistema per garantire che vi siano sempre un numero sufficiente di istanze in esecuzione e la gestione dei disastri, nel caso in cui una delle availability zone diventi indisponibile. Ad esempio, in questa immagine, l’autoscaling è composto da due istanze sparse su due availability zone. 

Nel caso una delle due availability zone avesse dei problemi, l’autoscaling gestirà la situazione creando la seconda istanza nell’altra availability zone: in questo modo abbiamo reso la nostra applicazione resiliente ai guasti di un intero data center.

Il punto su cui voglio soffermarmi è la creazione della Golden AMI: per semplificarne la creazione, AWS ha lanciato il servizio EC2 Image Builder, tramite il quale possiamo eseguire degli script o delle ricette che configurano il server per poi creare l’immagine finale desiderata. La nostra scelta su quale strumento usare per la configurazione del server è Ansible e in questo articolo AWS mostra come utilizzare EC2 Image Builder insieme ad Ansible.

Il processo di creazione dell’AMI è mostrato qui sotto: consiste nell’esecuzione di una istanza EC2 temporanea, l’esecuzione del playbook Ansible nell’istanza EC2 e infine una fase di validazione e la pubblicazione dell’immagine finale. 

Una volta ottenuta la Golden AMI è possibile aggiornare l’Auto scaling group ed effettuare il deployment della nuova versione.

Come fare il deploy della nuova immagine? Questo varia a seconda dello strumento usato per gestire l’infrastruttura: dai principali linguaggi di Infrastructure as Code (terraform, cloudformation) alla gestione manuale da console. In tutti i casi è possibile rilasciare la nuova immagine mediante una logica di rolling update, dove le istanze vengono aggiornate un po’ per volta in modo da effettuare l’aggiornamento senza fornire disservizio.

Conclusioni

Abbiamo visto un approccio alla gestione dei server che ci permette di avere diversi vantaggi sfruttando a pieno le potenzialità del cloud AWS. Nello specifico otteniamo i seguenti vantaggi:

  • Riduzione dei costi: potendo aumentare e diminuire a piacimento il numero di server che servono la mia applicazione in pochi secondi, ci permette di scegliere delle istanze con risorse minori e supplire ai momenti di picco aumentando le istanze. Questo permette di spendere considerevolmente meno nel caso in cui il carico applicativo segua dei cicli di picchi giornalieri.
  • Abilitare un processo automatizzato di creazione e verifica della configurazione dei server prima di ogni rilascio, aumentando la capacità di controllo, supervisione e trasparenza.
  • Garantisce che la configurazione dei server non si discosti con il tempo dalla configurazione desiderata e validata.
  • Abilita la possibilità di utilizzare tecniche di test avanzate come il Chaos Monkey.
  • Dà la possibilità di creare istanze di test identiche a quelle di produzione in pochi minuti per eventuali analisi o test.
  • Rende la nostra applicazione tollerante alla perdita di una o più availability zone (data center) con pochissimo sforzo e impegno economico.

Photo credits: FLY:D on Unsplash