Questo articolo ripercorre tutti i passaggi che hanno portato alla containerizzazione, partendo dai server, passando per le macchine virtuali per arrivare ai container. Verrà analizzata l’architettura Docker e in modo particolare come risolvere alcune insidie che si possono incontrare nell’utilizzo di questa tecnologia.
Questo articolo è il risultato della mia esperienza nella creazione e distribuzione di applicazioni dotnet e c# tramite macchine virtuali e nell’ultimo anno con Docker.
La prima volta che ho creato un’applicazione ho dovuto distribuirla tramite macchina virtuale e creare l’intero ambiente, partendo da zero, è stato particolarmente difficile e laborioso, senza considerare il fatto che fosse la mia prima esperienza.
Non molto tempo dopo, un giorno al lavoro, qualcuno mi disse che esisteva una sorta di “strumento magico” che ti permette di distribuire le applicazioni in pochi passaggi, semplicemente digitando alcuni comandi. Ovviamente pensavo che scherzasse e che mi prendesse in giro, ma invece era tutto vero, così da quel giorno tutto è cambiato!
In passato, se si voleva pubblicare online un’applicazione era necessario configurare letteralmente un computer e un servizio web dedicato, chiamato server. Ma con il passare del tempo, questo sistema rendeva molto difficile la gestione del software, e così sono arrivate le macchine virtuali (VM).
Una macchina virtuale non è altro che la virtualizzazione di un server fisico; ciò significa che le risorse hardware possono essere suddivise in più parti al fine di eseguire quelli che sembrano essere molti computer separati su hardware ma che in realtà è un solo computer. Come si può immaginare, tutto ciò può diventare molto costoso in termini di risorse hardware, hosting e tempo di installazione e configurazione della macchina, per non parlare del pesante utilizzo del sistema operativo.
Ad esempio, immaginiamo di installare WordPress in locale, per fare questo si dovrebbero eseguire numerosi passaggi prima di arrivare in fondo. E proprio per evitare questa lunga procedura è meglio utilizzare i container.
I Container possono essere considerati come una sorta di evoluzione delle macchine virtuali, che introduce importanti innovazioni nella tecnica tradizionale.
Il concetto è leggermente diverso da quello delle macchine virtuali, infatti i container condividono lo stesso kernel del sistema operativo e isolano i processi applicativi dal resto dell’infrastruttura. Questo sistema ottimizza l’utilizzo delle risorse e riduce la necessità di sistemi operativi ridondanti.
Come si può vedere dall’immagine, il componente principale della virtualizzazione, l’hypervisor, un software che gestisce tutte le macchine virtuali in esecuzione sulla macchina host, è stato sostituito da un nuovo componente, il container engine, che ha il compito di far girare i containers.
Docker è una piattaforma open source utilizzata per lo sviluppo, l’esecuzione e la distribuzione delle applicazioni con l’utilizzo dei container. Docker utilizza un’architettura di tipo Client-Server e questi sono i componenti principali:
Il client invia le richieste, digitate dall’utente, al server. I comandi docker utilizzano le API di Docker e il docker deamon resta in ascolto nell’attesa di nuove richieste e può trovare le immagini richieste su Docker Hub.
Ci sono tanti vantaggi nell’utilizzo dei containers, ecco qui i più importanti:
Come ho spiegato sopra, l’utilizzo di Docker porta molti vantaggi nello sviluppo e nella gestione di un’applicazione, ma ovviamente questo strumento non è la soluzione a tutto. Infatti ci sono molti scenari in cui è ancora preferibile continuare ad utilizzare le macchine virtuali. È opportuno pertanto definire in quali situazioni è meglio utilizzare Docker.
Prima di tutto se si ha a che fare con un’architettura di microservizi la containerizzazione è la scelta migliore. I microservizi sono un tipo di architettura che struttura l’applicazione come una raccolta di servizi. I sistemi software nascono generalmente come applicazioni monolitiche, in cui l’interfaccia utente e il codice di accesso ai dati sono combinati in un unico programma, ma con la crescita dell’applicazione, un monolite può diventare difficile da mantenere e distribuire. Al contrario i microservizi scompongono i sistemi in funzioni più semplici, che possono essere implementate in modo indipendente. Questo è il motivo per cui i container sono il miglior host per i microservizi, perché sono autonomi, facilmente implementabili ed efficienti.
Se si ha un team di sviluppatori che lavorano con configurazioni diverse, Docker dà la possibilità di avere ambienti di sviluppo locali simili a quelli di produzione.
Ed infine quando si ha la necessità di pubblicare l’applicazione su più fasi di sviluppo (dev, test, produzione).
MA, c’è un enorme “ma”, perché Docker può presentare anche degli svantaggi, come vedremo qui di seguito.
Nonostante Docker abbia così tanti vantaggi, è possibile però incontrare alcune insidie come:
Alcune di queste insidie possono essere risolte nel contesto in cui ci troviamo e in cui si sta sviluppando (come per esempio il discorso del debug), mentre altre, per esempio come scrivere correttamente un Dockerfile, sono problemi ricorrenti.
l segreto sta nel capire come costruire immagini e come orchestrale, ma prima di tutto dobbiamo definire alcuni termini importanti.
Un dockerfile è un file di testo che definisce un’immagine docker tramite una sintassi semplice e concisa. Mentre un’immagine docker è un modello di sola lettura contenente istruzioni per la creazione di un docker container, il quale è un’istanza di un’immagine docker. Ogni istruzione del dockerfile crea un livello sull’immagine e quando si modifica il dockerfile e si ricostruisce l’immagine, vengono ricostruiti soltanto i livelli che sono stati modificati.
In breve: devi scrivere un dockerfile per costruire un’immagine che esegue dei containers.
Di seguito un esempio di Dockerfile.
FROM node:8 WORKDIR /usr/src/app COPY package*.json RUN npm install COPY . . EXPOSE 8080 CMD ["npm", "start"]
Queste sono alcune delle principali istruzioni che si possono trovare in un Dockerfile:
Docker Compose è uno strumento di orchestrazione per applicazioni complesse con funzionalità minime.
Tuttavia, se si vuole utilizzare Docker Compose si deve
Ora, se prendiamo come esempio il problema di WordPress che ho presentato all’inizio, possiamo facilmente risolverlo con Docker Compose.
Qui abbiamo il file.
services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: somewordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress
All’inizio del file ci sono tutti i servizi di cui abbiamo bisogno per far funzionare WordPress, poi c’è la sezione di gestione dei dati (da notare la soluzione dei volumi che ho spiegato prima) e la sezione di WordPress con tutte le sue variabili d’ambiente.
Ed infine non resta che eseguire il comando docker-compose up.
Sicuramente Docker è uno strumento molto potente e all’avanguardia, ma come tutte le tecnologie, si deve saperlo usare nel modo giusto e prima ancora si deve sapere come funziona, perché altrimenti si rischia di non poter sfruttare al meglio tutte le potenzialità di questo strumento.
In sintesi: