Container, Docker & AWS Elastic Container Service

Cos'è un container e che differenza c'è tra un container ed una VM

Una delle tecnologie che riscuotono molto interesse nel panorama moderno è sicuramente Docker. Spesso si trovano le parole Docker e Container nello stesso contesto e si tende a confonderle, ma che differenza c'è e qual è il loro scopo?

Cerchiamo di fare un po' di chiarezza:

  • Container: un contesto di esecuzione isolato, che include il software desiderato, le sue dipendenze e l'ambiente in cui dovrà essere eseguito
  • Docker: è uno specifico software per la creazione, l’esecuzione e la gestione dei Container

Le tecnologie legate ai Container sono nate come risposta al problema di dover rilasciare una certa applicazione in contesti differenti in maniera affidabile. Prendiamo un tipico set-up di sviluppo e rilascio:

  1. il programma viene sviluppato sulle workstation degli sviluppatori (ogni sviluppatore potrebbe avere un ambiente diverso)
  2. rilasciato e testato su un server di test comune
  3. rilasciato e testato su un server di collaudo che cerca di riprodurre fedelmente l'ambiente di produzione
  4. rilasciato e messo a disposizione degli utilizzatori nell'ambiente finale

Anche ipotizzando che gli sviluppatori abbiano tutti la stessa workstation, il software prodotto migra tra 4 sistemi diversi. L'ipotesi di tenere tutti gli ambienti allineati si rivela spesso una pura utopia; l'esperienza insegna che avendo 4 obiettivi diversi saranno 4 ambienti diversi. Inoltre, anche assumendo di tenere tutti gli ambienti allineati, in caso di cambio del proprio fornitore di servizi Cloud o di Virtualizzazione potremmo non riuscire a replicare la stessa situazione in maniera identica. Come prima soluzione a questa problematica sono nati i sistemi di virtualizzazione dove è possibile creare una cosiddetta macchina virtuale che astrae tutte le componenti hardware in modo da poter avere una situazione completamente replicabile. La tipica struttura è schematizzata nel seguente grafico:

Hypervisor

Il sistema di virtualizzazione è quindi gestito da un Hypervisor che può operare direttamente sul hardware fisico (tipo 1) oppure aver bisogno a sua volta di lavorare all'interno di un sistema operativo (tipo 2). I principali svantaggi sono:

  • avere contemporaneamente in esecuzione più sistemi operativi completi occupa delle risorse che potrebbero essere disponibili per le applicazioni di interesse
  • non è garantita la portabilità delle macchine virtuali tra sistemi di virtualizzazione differenti

D'altro canto il mondo dei container è bastato sulla seguente architettura:

Container

I container condividono il kernel del sistema operativo che li ospita, mentre la user space è completamente separata e ridotta al minimo. In questo modo l'utilizzo delle risorse risulta più efficiente dato che viene ridotto l'impatto della tecnologia di gestione rispetto alla logica applicativa. Alcuni primi risultati che ne conseguono direttamente, se confrontati con la controparte realizzata a macchine virtuali, sono:

  • un miglioramento notevole del tempo di avvio (eliminato il tempo di boot del sistema operativo ospite)
  • può venir messo contemporaneamente in esecuzione un maggior numero di container

Dal punto di vista della portabilità dei container, nel 2015 è nato il progetto Open Container Initiative con l'obiettivo di mantenere e promuovere due standard in modo da uniformare i formati delle immagini dei container e le specifiche dei loro ambienti di esecuzione. Tra gli sponsor del progetto ci sono i principali protagonisti del cloud e della virtualizzazione.

Creazione di un Container con Docker

iot containers

Vediamo a questo punto quali sono i passi necessari per la creazione di container con Docker. Il processo può partire dall'immagine di un altro container che verrà usata come base oppure da una cartella vuota su filesystem. Nell'ultimo caso avremo pieno controllo di ciò che andrà a costituire il filesystem del container e andremo a creare una cosiddetta base image che potrà essere usata anche come base per altri container. Questa procedura incrementale per cui si può creare un nuovo container semplicemente arricchendone un altro consente un notevole risparmio di tempo e di risorse quando si creano più applicazioni a partire da una base comune. Inoltre esiste un repository pubblico Docker Hub su cui è presente una quantità elevata di immagini disponibili da cui poter cominciare lo sviluppo. La metafora usata per la gestione di questo repository è la stessa di Git per cui avremo le immagini che di fatto contengono solo le variazioni rispetto all'immagine precedente e potremo fare le operazioni di push e pull tra l'ambiente locale ed il server (esattamente come con le commit per Git).

I passi per la creazione di una nuova base image sono:

  1. creare una cartella vuota
  2. popolare la cartella con i file necessari all'esecuzione del software desiderato
  3. creare un archivio in formato “tar”
  4. creare l'immagine del container facendo l'import dell'archivio con l'omonimo comando di Docker

Ricordiamo che il contesto del container sarà limitato a ciò che abbiamo messo nell'archivio e quindi sarà nostra cura aver compilato il programma con link statici o aver incluso anche tutte le dipendenze necessarie. Una tipica immagine di base prevede l'installazione di tutte le componenti necessarie a far funzionare il package manager della propria distribuzione di riferimento, in modo da poter sfruttare nelle immagini derivate solo lo stretto indispensabile installato in base alla necessità.

Per eseguire un programma in un container si può utilizzare il comando docker run seguito dai parametri necessari all'individuazione dell'immagine e del programma da avviare.

Se invece si volesse creare un container a partire da un'altra immagine la procedura prevede di:

  • creare una cartella vuota
  • creare un file di testo col nome Dockerfile
  • specificare in quest'ultimo le operazioni necessarie alla creazione della nuova immagine
  • creare la nuova immagine col comando docker build e relativi parametri Il Dockerfile è molto simile ad uno script di shell in cui si indica ad esempio l'immagine da cui partire e le porte di rete da esporre.

AWS Elastic Container Service (ECS)

aws container

Diamo una rapida occhiata a cosa si possa fare su una piattaforma cloud come quella di Amazon (AWS). La sezione dei servizi a cui siamo interessati è quella denominata Elastic Container Service. In particolare abbiamo a disposizione:

  • Elastic Container Registry (ECR): dove è possibile definire dei repository per salvare le immagini dei container
  • Task definitions: un'area dove specificare tutti i parametri necessari a far funzionare correttamente un container
  • Clusters: l'ambiente dove andranno in esecuzione i container

Un primo utilizzo che può esser fatto di ECR è legato al servizio CodeBuild che consente di far compilare automaticamente del codice. L'ambiente in cui verranno eseguiti i comandi di compilazione è proprio dato da un container la cui immagine è salvata su ECR.

Un utilizzo invece più tradizionale dei container può esser fatto grazie ai Task definition ed ai Clusters. In particolare andremo a definire una Task definition in cui indichiamo l'immagine docker da eseguire e altri parametri tra cui i limiti di memoria, le porte di rete da esporre ed eventuali parti di filesystem da condividere tra il container ed il server su cui si trova.

Il Cluster può essere gestito autonomamente da Amazon ed in questo caso andremo a selezionare la tipologia Fargate oppure possiamo creare delle macchine virtuali (istanze EC2 se utilizziamo i termini di AWS) su cui installiamo docker ed un agent che registra l'istanza presso il cluster. A questo punto possiamo definire all'interno del cluster una delle seguenti modalità di esecuzione dei container:

  • Task: in caso l'applicazione nel container debba effettuare un'operazione una tantum (ad esempio per la conversione di video in modalità batch)
  • Service: in caso il software desiderato debba essere sempre attivo (come accade per un web server)
  • Scheduled Task: in caso si voglia lanciare un Task con cadenza periodica (come ad esempio per le procedure di backup)

Considerazioni finali

Il mondo dei container è molto più vasto di quello che è stato trattato in questo articolo, il cui principale obiettivo era porre le basi e dare qualche spunto di approfondimento. Un argomento molto interessante che avremo l'occasione di trattare in un futuro post riguarda sicuramente le architetture che sfruttano questa tecnologia.