Si fa presto a dire container.

Ma cosa si nasconde dietro una tecnologia ormai diventata a tutti gli effetti uno standard delle applicazioni moderne?

Le basi: cosa è Docker?

Cosa è Docker? Partiamo da una semplice definizione: Docker è una piattaforma open source che permette di automatizzare la costruzione, esecuzione e distribuzione di applicazioni mediante ambienti autoconsistenti chiamati container.

I container sono singole unità software che impacchettano il codice sorgente e tutte le sue librerie e dipendenze  e permettono di eseguire l’applicazione rapidamente, in modo affidabile e scalabile in qualsiasi ambiente.

L’applicazione all’interno del contenitore si considera l’unico processo in esecuzione sulla macchina, mentre la macchina può eseguire più contenitori in modo indipendente.

Il paragone con il mondo della logistica non è casuale: un container è un’unità standard sempre uguale, ma che può contenere qualsiasi cosa e ne permette la gestione in modo standardizzato a prescindere dall’ambiente in cui esso si trova.

Docker è una tecnologia mainstream ampiamente riconosciuta e documentata. La user base di Docker è cresciuta del 45% YoY nell’ultimo anno. Secondo il Docker Index, oggi gli account Docker ammontano a circa 7.5 milioni, ed è uno dei progetti più seguiti nel code repository GitHub, con oltre 20’000 stelle.

E inoltre…

Ma Docker è anche un’azienda? Sì, Docker, oltre che alla tecnologia, può riferire anche all’azienda (Docker Inc.), che gestisce la versione commerciale di Docker. Docker Inc. è un’azienda unicorno, valutata a oggi circa 1.5 miliardi di dollari.

Voglio lavorare con i container, devo usare Docker assolutamente o ci sono alternative? Sì, possiamo creare container anche senza utilizzare Docker direttamente, utilizzando prodotti come Podman, LXC, Containerd o Buildah.

Ma Docker gira solo su Linux? Sì, e no. Il Docker engine inizialmente si appoggiava su LXC (Linux Container), successivamente migrato su Cointanerd, e utilizza comunque componenti proprie del kernel Linux (cgroup per isolare le risorse, namespace per garantire l’indipendenza dei singoli applicativi). La compatibilità è assicurata grazie a macchine virtuali Linux che sono generate al momento dell’installazione di Docker sui diversi OS.

Ma quindi Docker crea una macchina virtuale?

Ok, bene. Ma quindi Docker è una sorta di macchina virtuale, giusto?

Beh, in parte.

Docker certamente si inserisce in un filone tecnologicamente consolidato, quello della virtualizzazione. Ma vediamo le differenze principali tra Docker e una Virtual Machine.

Cosa fa una virtual machine

>>>Una macchina virtuale riproduce digitalmente l’hardware sottostante un computer, allocando su questa immagine tutti i suoi elementi: CPU, RAM, schede di rete, hard disk, floppy disk, porte USB, ecc. Su tale hardware virtuale viene quindi eseguito il sistema operativo, gli applicativi, librerie, e quant’altro necessario.
Quindi, ciascuna macchina virtuale è un ambiente completo ma pesante in termini di tempo di avvio e di spazio fisico necessario. Più macchine virtuali sulla stessa macchina fisica necessitano comunque di replicare la totalità degli elementi presenti in ciascuna di esse. Il caso tipico è l’ambiente Windows che ha una distribuzione Linux che gira su una macchina virtuale.

La tecnologia sottostante una Virtual Machine è il componente hypervisor (tra i quali citiamo Hyper-V di Microsoft,  Xen, Virtual Machine Monitor open source, e ESX, lo standard Virtual Machine per il mondo enterprise).

Cosa fa un container

>>>Un container crea un ambiente virtuale a livello di sistema operativo. Condivide con l’host sottostante l’hardware e il kernel su cui viene fatto girare, in un contesto isolato, un sistema operativo quasi completo che, in genere, esegue un solo processo. Più container possono condividere quindi lo stesso sistema operativo e possono essere agevolmente spostati da una struttura all’altra, in modo efficiente in termini di quantitativi di memoria fisica e computazionale.

Docker vs Virtual Machine

>>>Una virtual machine offre quindi una virtualizzazione completa rispetto a un container (una macchina virtuale Linux può girare su un sistema Windows, ma un container Linux non può girare su un sistema Windows).

>>>Puoi usare un container per isolare applicazioni individuali, puoi usare una macchina virtuale per isolare un intero sistema operativo.

>>>Macchine virtuali sono (simili a) server, i container sono (simili a) processi.

>>>Puoi configurare un container mediante un file di configurazione relativamente semplice rispetto ai parametri di configurazione richiesti per configurare una virtual machine.

>>>Tipicamente una macchina virtuale è utilizzata per un ambiente che rimane relativamente stabile, mentre i container sono utilizzati per applicativi che necessitano di modifiche costanti, snelle e comparabili.

Ciò detto, ricordiamo che un container persegue obiettivi diversi rispetto a una macchina virtuale e quindi questo confronto va considerato a scopo didattico piuttosto che funzionale.

Esistono anzi diversi casi d’uso che vedono container e virtual machine integrati nella stessa architettura.

I componenti di Docker

L’architettura di Docker è composta da una serie di elementi tra loro correlati:

  • Docker engine
  • Docker client
  • Immagini Docker
  • Container Docker

Vediamo una rapida panoramica di ciascuna di queste componenti.

Docker Engine

Il vero cuore dell’architettura Docker, deputata a creare e eseguire i container Docker. È un’applicazione basata su una struttura client- server, composta da:

  • Server: il processo daemon (o demone, ossia processo informatico che gira in background senza necessità di input da parte dell’utente) chiamato Dockerd. Può creare e gestire immagini Docker, container, networks, etc.
  • Rest API:  fornisce l’interfaccia tra i programmi e l’engine, e lo scambio di comandi e informazioni (vuoi approfondire il tema? Vola qui)
  • CLI: ossia un’interfaccia a linea di comando (Command Line Interface)

Docker Client

Il client Docker (docker) è il modo principale con cui gli utenti Docker interagiscono con Docker. Quando si usano comandi come docker run, il client invia questi comandi a Dockerd, che li esegue. Il comando docker usa l’API di Docker, e ciascun client Docker può comunicare con più di un daemon.

Immagine Docker

Le immagini Docker sono modelli di sola lettura con istruzioni per creare un container Docker. L’immagine Docker può essere estratta da un hub Docker e usata così com’è, oppure si possono aggiungere ulteriori istruzioni all’immagine base e creare una nuova immagine Docker modificata. È possibile creare le proprie immagini docker anche utilizzando un dockerfile, ossia un file testuale che viene salvato però senza estensione e che contiene le istruzioni per la creazione dell’immagine.

Qui sotto trovi un esempio dove andiamo a definire l’immagine base (o anche parent image), in questo caso basata su una versione ultralight di Linux Alpine che pesa appena 5 mb!

Dopodiché, impostiamo le directory, copiamo i file e i pacchetti da utilizzare nella nostra immagine, e definiamo la porta alla quale il nostro container sarà raggiungibile dall’esterno.

FROM golang:1.6-alpine
RUN mkdir /app 
ADD . /app/ 
WORKDIR /app 
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
CMD ["/app/main"]
EXPOSE 80

Container Docker

A questo punto possiamo dire che un container altro non è che un’immagine in esecuzione. L’istanza di un’immagine. Un contenitore definito dalla sua immagine o dalle opzioni di configurazione che forniamo durante la sua creazione o esecuzione.

Per impostazione predefinita, un contenitore è ben isolato dagli altri contenitori e dalla sua macchina di sistema.

Immagini  e container vengono talvolta raggruppati nell’insieme degli Oggetti Docker.

I vantaggi dell’uso dei container

Ma a questo punto ci chiediamo: che vantaggi abbiamo dall’utilizzo dei container nella nostra architettura software?

Isolamento: i nostri applicativi vivono e mutano in un ambiente virtuale ben definito. Non dobbiamo preoccuparci di interdipendenze che possano andare a rompere o compromettere i componenti specifici funzionali alla loro esecuzione.

Risorse: i container permettono un utilizzo più parsimonioso di risorse costose come memoria e potenza computazionale.

Agilità: i container abilitano cicli di sviluppo del software rapidi, che incontrano mutuate necessità tecniche e requisiti di business differenti senza necessitare di costose riconfigurazioni. La natura stessa dell’architettura a container getta le basi per l’adozione di metodologie di lavoro DevOps e Agile.

Scalabilità: grazie alla logica insita nei container, in ciascun istante utilizziamo solo le risorse delle quali abbiamo bisogno, e possiamo rapidamente accedere al livello successivo in caso di aumento del volume (di traffico, di transazioni, di elaborazioni) sul nostro applicativo grazie al bilanciamento del carico (load balancer).

Portabilità: i container semplificano enormemente il rilascio in produzione degli applicativi. L’ambiente è già configurato al momento della creazione del container e pertanto diventa irrilevante su quale macchina esso stia girando, sia essa un’istanza cloud pubblica che il portatile nella nostra camera. Tutto ciò che è necessario all’esecuzione del software viene letteralmente spedito insieme (come un container, appunto!). Gli ambienti diventano standardizzati, nessuno potrà più dire “eh ma sul mio computer funzionava”.

Microservizi: l’utilizzo di applicativi istanziati su container porta allo sviluppo conseguente di una logica architetturale orientata ai servizi (SOA, Service Oriented Architecture)e da qui alla versione atomica dei servizi software, i microservizi. Ciascuna funzionalità viene isolata in un ambiente definito (il container) e comunica con il resto del mondo mediante protocolli come API REST.

Disaster Recovery: Docker consente di creare un backup di un container in esecuzione (lo “snapshot”) e di ripristinarlo successivamente in caso di problemi.

Ma quando invece Docker potrebbe non essere una buona idea?

Come molti altri fenomeni in ambito tecnologico, attorno a Docker c’è anche un discreto rumore di fondo dato da chi segue ciecamente l’ultimo trend senza porsi domande.

Docker non è uno strano incantesimo che renderà le tue applicazioni sicure, performanti e scalabili senza fatica. Anzi, talvolta usare Docker potrebbe essere anche controindicato.

Sviluppi applicativi desktop con una ricca interfaccia grafica: Docker non è adatto alle applicazioni che richiedono una ricca GUI. Docker è destinato principalmente a contenitori isolati con applicazioni basate su terminale.

Hai un progetto piccolo o molto semplice: se hai un progetto di dimensioni ridotte, applicando un’architettura a container avrai più svantaggi che benefici. Stessa cosa se sei uno sviluppatore indipendente che lavora con una pipeline di sviluppo tendenzialmente statica.

La sicurezza è la tua priorità numero uno: in parte per i motivi elencati nei pros della tecnologia a container, Docker potrebbe esporre i tuoi ambienti a problemi di sicurezza. Le applicazioni su Docker girano con privilegi di amministratore, pertanto potrebbero anche costituire una backdoor per la tua infrastruttura.

Il tuo team non ha esperienza con l’utilizzo di Docker: sembra banale, ma se il tuo team non ha le skill per usare in modo proficuo la containerizzazione, prima di portarla su progetti in produzione assicurati di aver speso il giusto tempo in formazione e esperienza.

Gestione di container: Kubernetes e Docker Swarm

Difficile parlare di Docker senza citare Kubernetes (che deriva dalla parola greca “timoniere” e ben si inserisce nel contesto marinaresco lanciato da Docker).

Kubernetes è una piattaforma open source per la gestione di container Linux aggregati e ad alto livello. Citando Fabio Ros:

Docker è il braccio e Kubernetes è la mente

Più precisamente Kubernetes offre un servizio di orchestrazione e gestione per distribuire i container, organizzarne il carico di lavoro, la sicurezza, il runtime, la reportistica, e svariati altri servizi.

Sebbene Kubernetes sia la soluzione che sta prendendo sempre più piede per l’orchestrazione di container, Docker offre una soluzione all’interno della sua piattaforma, Docker Swarm, che si focalizza su una configurazione maggiormente user-friendly.

Va inoltre precisato che Kubernetes ha deprecato Docker come container runtime dalla versione v1.20, favorendo invece l’utilizzo della CRI (Container Runtime Interface) create appositamente per Kubernetes. Gli aggiornamenti su questo tema si susseguono rapidamente e pertanto se il tema ti interessa, ad oggi ti consigliamo di seguirlo direttamente dalla fonte: Dockershim Removal FAQ.

Docker: un po’ di storia

Anche se il fenomeno della containerizzazione è esploso in tempi recenti, la storia che ha portato alla nascita di Docker container è molto più lunga e articolata.

Il primo seme è stato gettato addirittura nel 1979 con Unix V7, e precisamente con l’operazione chroot (change root). Questa operazione consentiva di cambiare la root directory per un singolo utente, ossia di creare una segregazione all’interno del sistema operativo host in un sotto percorso.

Passano gli anni e arriviamo già ai primi 2000. Qui con FreeBSD, un sistema operativo Unix-based, compare il concetto di Jail, un sistema di virtualizzazione che permette di segregare i processi in ambienti isolati, ciascuno con il proprio hostname e indirizzo IP. È possibile gestire molteplici servizi Jail in contemporanea, in modo indipendente, ma tutti condividono lo stesso kernel. Va detto che “container” è un nome molto più vendibile di “prigione”.

Successivamente si susseguono una serie di innovazioni che insistono sul filone della virtualizzazione: OpenVz, Solaris Container, Linux VServer, Process.

Infine nel 2008 arriva LXC (LinuX Container), la prima completa implementazione di un container manager su Linux, che getta le basi per Docker così come lo conosciamo oggi.

Docker vede la luce nel 2013. Uno storico talk, che dura appena 5 minuti (e che trovi qui sotto). Durante la conferenza dedicata al mondo Python, PyCon 2013, Solomon Hykes presenta “il futuro per i container Linux”, introducendo di fatto Docker (con un "while true: do echo hello wowlrd"(sic!)).

Docker è esploso di pari passi con l’esplosione della containerizzazione, o forse viceversa? Comunque sia la crescita è stata esponenziale.

Nel 2014 Google introduce Kubernetes, arrivando ufficialmente alla mass adoption.

Il futuro di Docker

Sarà Docker e la containerizzazione lo standard anche per i prossimi dieci anni?

Probabilmente il ruolo di Docker e della containerizzazione resterà importante.

Ma d’altra parte, c’è chi sta puntando anche sull’architettura serverless.

Ma questa è un’altra storia :)

Note: alla revisione e accuratezza tecnica di quest’articolo hanno contribuito gli amici della community di Nuvolaris, una distribuzione Apache OpenWhisk che gira in ogni Kubernetes. In particolare un ringraziamento a Michele Fadda e Federico Balice, che si sono offerti di darmi il loro prezioso punto di vista.

Scarica l’ebook “The Digital Transformation Workbook”

Iscriviti alla newsletter e scarica l’ebook.
Ricevi aggiornamenti e news sulla tecnologia e la strategia che permettono alle aziende di sfruttare al massimo la trasformazione digitale.