Introduzione a Docker: l’arma definitiva del sysadmin

Tra i progetti open-source più seguiti e discussi del momento c’è sicuramente Docker, che a ormai tre anni dal lancio fa ancora parlare di sé con dei numeri straordinariamente grandi.
Le sue statistiche su GitHub parlano chiaro:

  • oltre 20 000 stars
  • più di 1600 contributori tra programmatori, supporter e altri
  • più di 20 000 commit

docker-numbers-light

Ormai Docker è diventato sinonimo di container ed è lo standard di fatto tra gli addetti ai lavori.
L’audience di Docker sono sicuramente sviluppatori e sysadmin che affrontano quotidianamente problemi come ad esempio:

  • mantenere un ambiente consistente nell’iterazione tra le varie build
  • installare software che va in conflitto con le versioni sul sistema host
  • mantenere un sistema di testing consistente
  • cambiare configurazione della rete per i requisiti del sistema

Vediamo insieme come funziona e perché in che modo può aiutare sviluppatori e altri tecnici a svolgere il proprio lavoro.

Cos’è un “container”

Personalmente, ritengo che la cosa più semplice per capire cosa sia un container, sia compararlo alla virtualizzazione tradizionale.

Nella virtualizzazione tradizionale si parte dal hardware dove gira un sistema operativo nel quale è installato l’hypervisor che si occupa di emulare l’hardware e metterlo a disposizione alle varie macchine virtuali (d’ora in avanti VM).
Ogni VM include applicazioni, librerie e i binari necessari al suo funzionamento e infine l’intero sistema operativo “ospite”. I tutto può arrivare a pesare decine di Giga-byte.

I container funzionano in modo simile: si parte sempre dall’hardware e da un sistema operativo, poi le cose cambiano. Non c’è più un qualcosa che emula l’hardware ma vengono sfruttate alcune feature del kernel di Linux (namespaces, cgroups, chroots e altro) che permettono di ricavare dei piccoli “compartimenti a tenuta stagna”, nei quali i container vengono eseguiti come processi isolati all’interno dello userspace del sistema host.
I container al loro interno includono l’applicazione con tutte le sue dipendenze e, poiché condividono il kernel tra loro, non hanno bisogno di embeddare anche un sistema operativo dedicato, ma sfruttano quello del sistema host. Il risultato sono delle immagini estremamente leggere che non sono legate a nessuna infrastruttura particolare, perciò sono estremamente portabili.
In soldoni i container dal punto di vista applicativo funzionano come la virtualizzazione tradizionale ma senza l’overhead dell’hypervisor e del sistema operativo.

vm-vs-container

Cos’è Docker e come può aiutarci

I container sono veramente belli, ma gestirli e usarli è sempre stato un problema soprattutto causato dall’assenza di standard. Ed è qui che entra in scena Docker.
Docker non è un un semplice programma, ma è un insieme di tecnologie che cooperano al fine di standardizzare il formato dei container e avere un toolchain chiaro e ordinato, quindi efficiente.

Prima di tutto c’è il Docker engine, il demone che risiede sul server e accetta comandi da un client, sia essa una utility a riga di comando o una chiamata alle API. Questo demone comunica con il Kernel Linux attraverso la libreria libcontainer, anch’essa parte del progetto.
Infine c’è il registry, una piattaforma che risiede nel cloud (ad esempio quella ufficiale: Hub) e che fornisce un’area dove caricare, scaricare e condividere le immagini dei vari container.

Funzionamento di base

Supponiamo di voler avviare un container con una determinata immagine: il client chiede al server di prendere quella immagine specifica e “iniettarla” in un container. Il server, che non possiede ancora quell’immagine, contatta il registry e la scarica creandone una copia cache locale ed infine la inietta in un container. Il container può essere avviato come si avvierebbe una VM, passando variabili di ambiente, effettuando il mapping di porte e così via.

docker-parts

Sviluppo stratificato

A mio parere la vera forza di Docker è che permette di sviluppare applicazioni in modo stratificato. Mi spiego con un esempio:

partendo da un’immagine CentOS si possono creare due immagini che la usano come base: una con Apache e una con Nginx. A quella con Apache impilarne una terza con un MySQL e poi una quarta con WordPress. Poi si può fare una cosa simile partendo da quella con Nginx. E così via, spazio alla fantasia!

Come si capisce da questo esempio (spero!) questo sistema permette di isolare le dipendenze gestendo così al meglio il proliferare delle versioni di librerie e software senza troppi grattacapi, il tutto con pochi e semplici comandi.
E questo ci porta al prossimo paragrafo che descrive un workflow tipico.

Un workflow tipico

Quante volte avete sentito la tipica frase:

Eh, ma sulla mia macchina funzionava!

Bene, con Docker mai più!
Prendiamo l’applicazione, isoliamone le dipendenze e sbattiamola in un container (facendo attenzione a non romperla 🙂 )
Partendo da questa base il programmatore comincia a fare modifiche e quando è contento passa la patata bollente al povero tester. In questo caso però il tester è sicuro che il container funziona e, stratificando le sue dipendenze sopra all’immagine di partenza effettua tutti i test che deve. A test effettuati il container che proviene dal programmatore può andare in produzione dove molto probabilmente verrà espanso con librerie o configurazioni extra.

31-docker-workflow-overview

Questo è solo un esempio anche abbastanza semplice di come Docker possa tornare utile all’interno di un contesto dello sviluppo di un’applicazione, ma ci sono altri campi in cui può trovare applicazione.

Considerazioni finali

Docker costa sicuramente meno, in termini di risorse, rispetto a soluzioni di virtualizzazione più tradizionali.
Docker conferisce un sicurezza maggiore alle applicazioni che girano in un ambiente condiviso poiché le isola,ma non bisogna mai dimenticare di utilizzare tutte le best practise in ambito di sicurezza o si finirà per finire comunque gambe all’aria!
Il più importante vantaggio che questa tecnologia promette è la portabilità e la consistenza di un formato che consente l’esecuzione dei container su diverse piattaforme e host.
Le applicazioni possono essere facilmente spostate in modo più economico e veloce, evitando anche i problemi causati dalle caratteristiche delle piattaforme o dalle restrizioni dei singoli provider.