Docker: la tecnologia container rivoluzionaria

Docker è una tecnologia per la virtualizzazione di applicazioni software basata su container. L’approccio mainstream basato sui container di Docker ha trasformato lo sviluppo di applicazioni negli ultimi anni. Questo ha infatti influenzato tutte le diverse aree di sviluppo, compreso il modo in cui le applicazioni e i componenti sono costruiti e i servizi software distribuiti, spostandoli dallo sviluppo alla produzione. Con Docker, tutti questi processi vengono eseguiti in modo diverso rispetto a prima.

Non sono cambiati solo i processi di sviluppo ma anche l’architettura del software, spostandosi da soluzioni globali monolitiche verso cluster di “microservizi” leggeri. Questo a sua volta ha reso i sistemi risultanti più complessi. Negli ultimi anni, il software Kubernetes si è affermato per gestire applicazioni multi-container.

Lo sviluppo della virtualizzazione basata su container è lungi dall’essere finito, rimanendo quindi un settore entusiasmante. In questo articolo, vi spiegheremo come funziona Docker come tecnologia di base e vedremo cosa ne ha motivato lo sviluppo.

N.B.

Il nome “Docker” ha diversi significati. È usato come sinonimo del software stesso, per designare il progetto open source su cui si basa e per indicare una società statunitense che gestisce commercialmente vari prodotti e servizi.

Una breve storia di Docker

Il software originariamente rilasciato con il nome di “Docker” è stato costruito sulla base della tecnologia Linux Container (LXC). LXC è stata poi sostituita dalla libcontainer, propria di Docker. Nel tempo sono stati aggiunti nuovi componenti software mentre Docker ha continuato a crescere e a diventare lo standard per la virtualizzazione basata su container. Dallo sviluppo di Docker sono emerse caratteristiche come containerd, un runtime per container con l’implementazione predefinita runC. Oggi, entrambi i progetti sono gestiti dalla Cloud Native Computing Foundation (CNCF) e dalla Open Container Initiative (OCI).

Oltre al team Docker, aziende tecnologiche leader come Cisco, Google, Huawei, IBM, Microsoft e Red Hat sono coinvolte nello sviluppo di Docker e delle tecnologie correlate. Inoltre, ora anche Windows è utilizzato come ambiente nativo per i container Docker, oltre al kernel Linux. Di seguito riportiamo alcune delle principali tappe nella storia evolutiva di Docker:

Anno Tappe fondamentali nello sviluppo di Docker
2007 Tecnologia cgroups integrata nel kernel Linux
2008 Rilascio di LXC; tecnologia basata su cgroup e namespace Linux come è avvenuto per Docker in seguito
2013 Rilascio di Docker come open source
2014 Docker diventa disponibile su Amazon EC2
2015 Rilascio di Kubernetes
2016 Docker disponibile su Windows 10 Pro via Hyper-V
2019 Docker disponibile su Windows Home via WSL2
Consiglio

Alla fine dell’articolo si discuterà in dettaglio di ciò che ha motivato lo sviluppo di Docker e le tecnologie di virtualizzazione simili.

Cos’è Docker?

La funzionalità principale di Docker è la virtualizzazione basata su container delle applicazioni. Questo è in contrasto con la virtualizzazione eseguita con macchine virtuali (VM). Con Docker, il codice dell’applicazione, comprese tutte le dipendenze, è impacchettato in un’immagine. Il software Docker esegue l’applicazione impacchettata in un container Docker. Le immagini possono essere spostate tra i sistemi ed eseguite su qualsiasi sistema che esegue Docker.

Citazione

“Containers are a standardized unit of software that allows developers to isolate their app from its environment […]“ – Affermazione di uno sviluppatore Docker, fonte: https://www.docker.com/why-docker

“I container sono un’unità standardizzata di software che permette agli sviluppatori di isolare la loro applicazione dal suo ambiente [...]” – (Traduzione: IONOS)

Come nel caso della distribuzione delle macchine virtuali (VM), un obiettivo primario dei container Docker è quello di isolare l’applicazione in esecuzione. A differenza delle VM, tuttavia, non viene virtualizzato il sistema operativo completo. Invece, Docker alloca alcune risorse del sistema operativo e dell’hardware a ogni container. Un’immagine Docker può creare un qualsiasi numero di container ed eseguirli parallelamente. Questo è il modo in cui vengono implementati i servizi cloud scalabili.

Anche se si parla di Docker come un unico software, in realtà si tratta di più componenti software che comunicano attraverso l’API del Docker Engine. Inoltre, viene utilizzata una manciata di oggetti Docker speciali, come le già citate immagini e i container. I workflow specifici di Docker sono composti da componenti software e oggetti Docker. Diamo un’occhiata a come interagiscono in dettaglio.

Software Docker

La base del software Docker è il “Docker-Engine”. Questo è usato principalmente per gestire e controllare i container e le immagini sottostanti. Per delle funzionalità ulteriori vengono usati degli strumenti speciali, necessari principalmente per gestire le applicazioni che consistono in gruppi di container.

Docker Engine

Il Docker Engine viene eseguito su un sistema locale o su un server e consiste di due componenti:

  1. Il demone Docker (Dockerd): è sempre in esecuzione in background e scansiona le richieste API del Docker Engine. Dockerd risponde ai comandi appropriati per gestire i container e altri oggetti Docker.
  2. Il client Docker (Docker): è un programma a riga di comando. Il client Docker è usato per controllare il Docker Engine e fornisce comandi per creare e costruire container Docker, così come creare, ottenere ed effettuare il controllo delle versioni delle immagini Docker.

Docker Engine API

L’API del Docker Engine è un’API REST che si interfaccia con il demone Docker. Per integrare l’API del Docker Engine in progetti software sono disponibili “kit di sviluppo software” (SKD) ufficiali per Go e Python. Esistono anche librerie simili per più di una dozzina di altri linguaggi di programmazione. È possibile accedere all’API tramite la riga di comando utilizzando il comando Docker. Inoltre, potete accedere direttamente all’API utilizzando cURL o strumenti simili.

Strumenti Docker

Quando si usano macchine virtuali, spesso si usano sistemi composti da diversi componenti software. Al contrario, la virtualizzazione basata su container di Docker favorisce la formazione di cluster di microservizi liberamente accoppiati. Questi sono adatti a soluzioni cloud distribuite che offrono un alto grado di modularità e alta disponibilità. Tuttavia, questi tipi di sistemi diventano sempre più complessi. Per gestire le applicazioni containerizzate in modo efficiente, si utilizzano strumenti software speciali noti come “orchestratori”.

Docker Swarm e Docker Compose sono due strumenti ufficiali di Docker disponibili per orchestrare cluster di container. Il comando “Docker swarm” può essere utilizzato per combinare più motori Docker in un motore virtuale. I singoli motori possono quindi essere gestiti su più sistemi e infrastrutture. Il comando “Docker compose” è usato per creare applicazioni multi-container note come “stack”.

L’orchestratore Kubernetes, originariamente sviluppato da Google, è più user-friendly di Swarm e Compose. Per questo motivo è quindi diventato uno standard ampiamente utilizzato nell’industria IT. Le società di hosting e altri fornitori di soluzioni “Software as a Service” (SaaS) e “Platform as a Service” (PaaS) utilizzano sempre più Kubernetes come infrastruttura sottostante.

Oggetti Docker

I workflow nell’ecosistema Docker sono il risultato di come gli oggetti Docker interagiscono tra loro. Questi vengono gestiti tramite la comunicazione con l’API del Docker Engine. Di seguito esaminiamo ogni tipo di oggetto in dettaglio.

Immagine Docker

Un’immagine Docker è un modello di sola lettura volto a creare uno o più container identici. Le immagini Docker sono fondamentalmente i semi del sistema, utilizzate per impacchettare e distribuire le applicazioni.

Per condividere le immagini Docker vengono utilizzati vari repository. Esistono sia repository pubblici che privati. In data corrente, esistono più di cinque milioni di immagini diverse disponibili per il download sul popolare servizio “Docker Hub”. I comandi Docker “Docker pull” e “Docker push” sono usati per scaricare un’immagine da un repository o per condividerla.

Le immagini Docker sono costruite a livelli. Ogni livello rappresenta un cambiamento specifico dell’immagine. Questo si traduce in un continuo controllo delle versioni delle immagini, che permette un rollback a uno stato precedente. Un’immagine esistente può essere usata come base per crearne una nuova.

Dockerfile

Un Dockerfile è un file di testo che descrive la struttura di un’immagine Docker. Un Dockerfile è simile a uno script di elaborazione batch, cioè il file contiene comandi che descrivono un’immagine. Quando si esegue un Dockerfile, i comandi vengono elaborati uno dopo l’altro. Ogni comando crea un nuovo livello nell’immagine Docker. Quindi si può anche pensare a un Dockerfile come a una sorta di ricetta usata come base per creare un’immagine.

Container Docker

Ora passiamo al concetto principale dell’universo Docker: i container Docker. Mentre un’immagine Docker è un modello inerte, un container Docker è un’istanza attiva e in esecuzione di un’immagine. Un’immagine Docker esiste localmente in una singola copia e occupa uno spazio di archiviazione minimo. Al contrario, una stessa immagine Docker può creare diversi container che possono a loro volta essere eseguiti allo stesso tempo.

Ogni container Docker consuma una certa quantità di risorse di sistema per poter funzionare, come l’uso della CPU, la RAM, le interfacce di rete, ecc. Un container Docker può essere creato, avviato, fermato e distrutto. È anche possibile salvare lo stato di un container in esecuzione come una nuova immagine.

Volume Docker

Come abbiamo visto, un container Docker in esecuzione viene creato a partire da un’immagine non modificabile. Che dire invece dei dati che vengono utilizzati all’interno del container e devono essere conservati oltre la sua vita utile? In questo caso vengono utilizzati i volumi Docker. Un volume Docker esiste al di fuori di un container specifico. Quindi diversi container possono condividere un volume. I dati contenuti nel volume sono archiviati sul file system dell’host. Ciò significa che un volume Docker è come una cartella condivisa su una macchina virtuale.

Come funziona Docker?

Il principio di funzionamento di base di Docker agisce in modo simile alla tecnologia di virtualizzazione LXC precedentemente sviluppata: entrambi si basano sul kernel Linux ed eseguono la virtualizzazione basata su container. Sia Docker che LXC combinano due obiettivi contraddittori:

  1. I container in esecuzione condividono lo stesso kernel Linux, rendendoli più leggeri delle macchine virtuali.
  2. I container in esecuzione sono isolati l’uno dall’altro e hanno accesso solo a una quantità limitata di risorse di sistema.

Per raggiungere questi obiettivi, sia Docker che LXC fanno uso dei cosiddetti “kernel namespace” e “gruppi di controllo” (Control Groups). Diamo un’occhiata a come funziona questo processo in dettaglio.

Kernel Linux

Il kernel Linux è il componente centrale del sistema operativo open source GNU/Linux e in quanto tale gestisce l’hardware e controlla i processi. Quando si esegue Docker al di fuori di Linux, è necessario ricorrere all’utilizzo di un hypervisor o di una macchina virtuale che fornisca la funzionalità del kernel Linux. Su macOS viene utilizzato xhyve, un derivato dell’ipervisore BSD bhyve. Su Windows 10, Docker utilizza l’hypervisor Hyper-V.

Kernel namespace

I namespace sono una caratteristica del kernel Linux. Essi dividono le risorse del kernel assicurando così che i processi rimangano separati gli uni dagli altri. Un processo effettuato in un namespace può accedere solo alle risorse del kernel di quello stesso namespace. Di seguito vi mostriamo una panoramica dei namespace utilizzati su Docker:

Namespace Descrizione Spiegazione
UTS Identificazione di sistema Assegna ai container i nomi host e di dominio
PID ID di processo Ogni container usa il proprio namespace per gli ID di processo; i PID di altri container non sono accessibili; in questo modo, due processi in container diversi possono usare lo stesso PID senza entrare in conflitto.
IPC Comunicazione interprocessuale I namespace IPC isolano i processi in un container in modo che non possano comunicare con i processi in altri container.
NET Risorse network Assegna risorse di rete separate come indirizzi IP o tabelle di routing a un container
MNT Punti di montaggio del file system Limita il file system dell’host a una sezione strettamente definita dal punto di vista del container

Gruppi di controllo

I gruppi di controllo, di solito abbreviati come cgroup, sono usati per organizzare gerarchicamente i processi Linux. A un processo (o gruppo di processi) viene assegnata una quantità limitata di risorse di sistema che include RAM, core della CPU, memoria di massa e dispositivi di rete (virtuali). Mentre i namespace isolano i processi l’uno dall’altro, i gruppi di controllo limitano l’accesso alle risorse di sistema. Questo assicura che l’intero sistema rimanga funzionale quando si utilizzano più container.

Quali sono i vantaggi di Docker?

Diamo uno sguardo alla storia dello sviluppo del software per capire i vantaggi di Docker. Com’è e com’è stato costruito, fornito ed eseguito il software? Quali parti del processo sono cambiate drasticamente? Il software è la controparte dell’hardware, il computer fisico. Senza software, il computer è solo un grumo di materia. Mentre l’hardware è fisso e immutabile, il software può essere ricreato e personalizzato. L’interazione dei due livelli risulta nel meraviglioso mondo digitale.

Software su una macchina fisica

Tradizionalmente, il software è stato creato per essere eseguito su una macchina fisica. Tuttavia, si possono riscontrare alcune difficoltà. Il software può essere eseguito solo su un certo hardware e può, ad esempio, richiedere un certo processore.

Inoltre, dei software più complessi di solito non funzionano in modo completamente autonomo, ma sono integrati in un ecosistema software. Questo include un sistema operativo, librerie e dipendenze. Affinché queste possano interagire correttamente, bisogna che siano disponibili le giuste versioni di tutti i componenti. Esiste anche una configurazione che descrive come i singoli componenti sono collegati tra loro.

Se volete eseguire diverse applicazioni parallelamente su una macchina, sorgono rapidamente dei conflitti di versione. Un’applicazione può richiedere una versione di un componente che è incompatibile con un’altra applicazione. Nel peggiore dei casi, ogni applicazione dovrebbe essere eseguita su una diversa macchina fisica. Tuttavia, le macchine fisiche sono costose e non possono essere scalate facilmente. Quindi molte volte, se i requisiti in termini di risorse di un’applicazione crescono, è necessario optare per una nuova macchina fisica.

Un altro problema deriva dal fatto che il software in sviluppo è usato in diversi ambienti. Uno sviluppatore scrive il codice sul sistema locale e lo testa nello stesso sistema. L’applicazione passa attraverso diverse fasi di test prima di andare in produzione, incluso un ambiente di test per la garanzia della qualità o un ambiente di staging per essere testato dal team di prodotto.

Inoltre, i diversi ambienti spesso esistono su diverse macchine fisiche. Ciò comporta quasi sempre delle differenze nelle versioni del sistema operativo, delle librerie e nella configurazione. Come si può conciliare tutto questo? Per giunta, se gli ambienti differiscono l’uno dall’altro, i test perdono il loro valore e se un sistema non funziona correttamente deve essere sostituito. Come si può garantire una certa coerenza? Affrontare questi problemi su macchine fisiche è molto difficile.

Macchine virtuali: un passo nella giusta direzione

I problemi appena citati relativi alle macchine fisiche hanno portato all’aumento della popolarità delle macchine virtuali (VM). L’idea di base è quella di integrare un livello tra l’hardware e il sistema operativo o il sistema operativo host e i sistemi operativi guest. Una VM disaccoppia l’ambiente applicativo dall’hardware sottostante. La specifica combinazione di sistema operativo, applicazione, librerie e configurazione può essere riprodotta da un’immagine. Oltre a isolare completamente un’applicazione, questo permette agli sviluppatori di raggruppare diverse applicazioni in un “dispositivo”.

Le immagini delle VM possono essere spostate tra le macchine fisiche e più sistemi operativi virtualizzati possono essere eseguiti parallelamente. Questo assicura che l’applicazione sia scalabile. Tuttavia, la virtualizzazione del sistema operativo richiede molte risorse ed è eccessiva per utilizzi semplici.

I vantaggi della virtualizzazione basata su container di Docker

Le immagini usate nella virtualizzazione basata su container non hanno bisogno di un sistema operativo. La virtualizzazione basata su container è più leggera e fornisce quasi lo stesso isolamento delle VM. Un’immagine container combina il codice dell’applicazione con tutte le dipendenze necessarie e la configurazione giusta. Le immagini sono portabili tra sistemi e i container costruiti su di esse possono essere riprodotti. I container possono essere usati in vari ambienti, come sviluppo, produzione, test e staging. Il controllo della versione dei livelli e delle immagini fornisce anche una buona dose di modularità.

Di seguito riassumiamo i vantaggi chiave della virtualizzazione delle applicazioni basata su Docker rispetto all’uso di una VM. Un container Docker:

  • non contiene il proprio sistema operativo e l’hardware simulato;
  • condivide il kernel del sistema operativo con altri container ospitati sullo stesso sistema;
  • è leggero e compatto in termini di utilizzo delle risorse rispetto a un’applicazione basata su VM;
  • si avvia più velocemente di una macchina virtuale;
  • può essere eseguito in più istanze della stessa immagine allo stesso tempo;
  • può essere usato insieme ad altri servizi basati su container tramite orchestrazione;
  • è ideale per lo sviluppo locale.
Per offrirti una migliore esperienza di navigazione online questo sito web usa dei cookie, propri e di terze parti. Continuando a navigare sul sito acconsenti all’utilizzo dei cookie. Scopri di più sull’uso dei cookie e sulla possibilità di modificarne le impostazioni o negare il consenso.