Docker compose – come orchestrare diversi container

Docker compose
L'avvento dell'architettura a microservizi e della metodologia DevOps ha creato la necessità di virtualizzazione a livello di sistema operativo. Mediante Docker Compose possiamo creare applicazioni anche molto complesse basate sui container e gestire le interdipendenze. Scopriamo mediante un esempio basato su Wordpress come fare.

Share

Reading time: 5 minutes

La tecnologia Docker ha permesso negli ultimi anni di semplificare il lavoro di sviluppo e messa in produzione di diversi applicativi. Specialmente con l’avvento dei microservizi e delle DevOps, la creazione di container per isolare i diversi servizi è risultata una scelta vincente. Come abbiamo visto nell’articolo Introduzione a Docker, Docker ha diverse caratteristiche e potenzialità. Tuttavia nell’altro articolo ci siamo soffermati sulla creazione di un singolo container mediante il Dockerfile. Poiché molte applicazioni moderne necessitano di più componenti, impostare un intero progetto su singoli Dockerfile può risultare molto complicato. Vediamo come il Docker Compose può aiutare nella gestione di più servizi interconnessi tra di loro.

Perché usare il Docker Compose

Ad oggi qualsiasi software è composto da diversi componenti. Ad esempio, un sito web costruito con WordPress necessita di un servizio adibito all’esecuzione della piattaforma, un database e un web server (ad esempio nginx). Questi 3 componenti devono essere attivi contemporaneamente e devono agire su una rete che li metta in comunicazione tra di loro. Se analizziamo altri software, la situazione può diventare molto più complicata. Negli ultimi anni, basandosi sul paradigma divide et impera, le applicazioni vengono sviluppate con un’architettura a microserizi. Quindi, non viene costruito un “mega” software che contiene tutta l’applicazione, ma si sviluppano tanti piccoli moduli. Ogni modulo ha un preciso compito e comunica con gli altri moduli qualora è necessario. In questo modo l’applicazione può crescere man mano e la manutenzione può essere mirata ai moduli di interesse. Infine, l’intero progetto può essere distribuito su diversi server per ottimizzare le prestazioni.

Questi esempi mostrano come in qualsiasi applicazione è necessario orchestrare in modo opportuno i vari componenti/servizi. Mentre con Docker è molto facile personalizzare i container, non è altrettanto semplice gestire le interdipendenze. Infatti, lo sviluppatore e/o l’amministratore del sistema dovrebbe costruire le varie immagini, creare le reti necessarie e, infine, eseguire l’applicazione mediante una serie di comandi Docker in un ordine prestabilito. Le possibilità di errore umano durante tutto questo processo aumentano esponenzialmente. Bisogna pertanto automatizzare il processo.

Il Docker Compose è uno strumento per definire, ed eseguire applicazioni multi-contenitore. I contenitori, chiamati anche servizi, vengono descritti in un file YAML. Vengono anche definite le loro relazioni. Il Docker Compose analizza questo file ed esegue i comandi definiti al suo interno. Ma non è l’unica funzionalità di questo strumento. Possiamo anche fermare e riavviare tutto il progetto o un singolo container, leggere il log dei vari container in esecuzione, visualizzare lo stato di un container specifico. Poiché ogni Compose file definisce un progetto, è possibile isolare progetti diversi e analizzare la loro coesistenza sulla stessa infrastruttura.

Versioni del Docker Compose file

Come abbiamo detto il Docker Compose necessita di un file YAML per descrivere i container da gestire. Esistono diverse versioni che sono state rilasciate nel corso degli anni. E’ possibile usare una delle versioni qui sotto riportate. Nonostante ciò vi suggeriamo di usare l’ultima disponibile.

Versione 1

La versione 1 è quella più vecchia. Tutti i file YAML che non specificano la versione vengono considerati appartenenti a questa tipologia. Attenzione che nelle prossime release potrebbe essere rimossa in quanto già deprecata. Questa versione presenta anche alcuni svantaggi:

  • i file della versione 1 non possono dichiarare i servizi, i volumi o gli argomenti di build nominati
  • la scoperta del contenitore è abilitata solo utilizzando il flag dei link

Versione 2

Per definire che si vuole utilizzare la versione 2 bisogna specificare come valore del campo version un valore uguale a 2 o 2.x. Rispetto alla versione precedente, introduce alcune modifiche che non premettono la portabilità diretta dalla versione 1. Infatti, nella versione 2 tutti i container si trovano su una rete predefinita specifica dell’applicazione e i container possono essere scoperti dal nome dell’host specificato dal nome del servizio. L’attributo links è reso ridondante, mentre viene introdotto il flag depends_on, che permette di specificare le dipendenze tra i container.

Versione 3

L’ultima versione disponibile è la 3 e deve essere specificata mediante il valore 3 o 3.x. In questa versione alcune opzioni, già deprecate nella versione 2, sono state rimosse (ad esempio volume_driver, volumes_from). Viene introdotta una chiave deploy utilizzata per la distribuzione e l’esecuzione di servizi su Docker Swarm.

Esempio di un docker compose con WordPress

Per comprendere al meglio la definizione dei servizi in un Docker Compose file andremo ad analizzare un esempio molto utile per chi sviluppa e gestisce siti web. Nel particolare vedremo un progetto WordPress.

Passo 1: Creare il progetto

Per prima cosa bisogna creare il progetto. Per far ciò basta semplicemente creare una directory con il nome del progetto come ad esempio my_wordpress.
Questa directory sarà il contesto dell’immagine dell’applicazione e deve, come visto nelle raccomandazioni per il Docker file nell’articolo X, contenere solo le risorse strettamente necessarie all’immagine.

Passo 2: Creazione del docker compose file

Poiché questo progetto dovrà contenere solo i servizi necessari all’esecuzione di un sito WordPress, la cartella conterrà solo il file docker-compose.yml. Nessuna altra risorsa sarà necessaria. Nel file descriveremo i servizi necessari come mostrato di seguito.

version: '3.3'

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
volumes:
    db_data: {}
 

Analisi del Docker Compose file

Analizziamo nel dettaglio le varie voci che abbiamo introdotto nell’esempio.

Come detto in precedenza all’inizio del file bisogna specificare la versione del Docker compose file. In questo caso specifichiamo che la versione è la 3.3. Se però si vuole essere più generali si può usare semplicemente 3.

Poiché si usa la versione 3 si devono definire i servizi. Nel caso di un’installazione di WordPress possiamo definirne 2: uno relativo al database mentre l’altro di WordPress. Per ogni servizio dobbiamo assegnare un nome a nostro piacimento. Il nome del container, se non specificato diversamente dalla proprietà container_name, sarà il nome del progetto concatenato con il nome del servizio.

Per ogni servizio definito è necessario specificare su quale immagine dovrà essere costruito. Nel caso analizzato si utilizzano delle immagini già disponibili sul Docker Hub. Per il database si utilizzerà un’immagine di mysql relativa alla versione 5.7, mentre per WordPress l’ultima immagine disponibile. Al momento della stesura dell’articolo l’immagine include Apache, PHP versione 7.4 e WordPress versione 5.6. Se invece si vuole utilizzare un’immagine definita da noi mediante un Dockerfile, bisognerà specificare mediante la proprietà build il path in cui è contenuto il Dockerfile e i file che verranno utilizzati.

Un’altra proprietà che di solito viene utilizzata è environment. Questo attributo specifica le variabili d’ambiente del container. In questo modo si può customizzare il container in base alle proprie esigenze. Nell’esempio riportato si usano delle variabili d’ambiente (definite nella documentazione dell’immagine) per impostare le credenziali per mysql e il nome del database da utilizzare per WordPress.

L’attributo depends_on indica le dipendenze tra i vari container in modo tale che un container non venga avviato fino a quando il container da cui dipende non sia disponibile. In questo caso, affinché il sito in WordPress funzioni correttamente, il servizio non deve essere attivato fintanto che il database mysql non sia disponibile.

Ogni container per definizione è un ambiente isolato. Affinché possa comunicare con gli altri container o possa essere acceduto tramite le porte dell’host è necessario specificare le proprietà expose e ports. Expose serve per mettere in ascolto il container su determinate porte. Queste possono essere definite nel Dockerfile dell’immagine o anche nel Docker Compose file. Solo i container appartenenti allo stesso progetto, o registrati sulla stessa rete (network), potranno cominciare con il container di riferimento su quella porta. Differentemente, la proprietà ports mappa le porte dell’host su quelle del container.

Per garantire che i container si riavviino in modo automatico qualora avvenga un interruzione del servizio, è consigliabile inserire il comando restart: always.

Infine, per salvare correttamente i dati del database abbiamo bisogno di un volume. Infatti, come abbiamo detto nell’articolo XX, i cambiamenti di stato vengono salvati all’interno del container. Per definire un volume dobbiamo specificarlo sotto la voce volumes, mentre per utilizzarlo nel container bisogna associare il volume ad un path all’interno del container. Nell’esempio abbiamo associato il volume chiamato db_data al path /var/lib/mysql dove vengono salvati i dati da mysql.

Questo è uno dei tanti esempi che si possono fare. Potete trovarne altri nella documentazione ufficiale. Il consiglio è di partire da questi esempi modificandoli in base alle vostre esigenze di progetto.

Letture consigliate

More To Explore

Intelligenza artificiale

AI: le migliori tecniche di prompt per sfruttare i LLM

Le tecniche di prompt sono alla base dell’uso dei LLM. Esistono diversi studi e linee guide per ottenere i migliori risultati da questi modelli. Analizziamo alcuni di essi per estrarre i principi fondamentali che ci permetteranno di ottenere le risposte desiderate in base al nostro compito.

Intelligenza artificiale

AI: creare un chatbot con i propri dati

ChatGPT ci permette di avere un assistente virtuale a nostra completa disposizione. Ha però una grande limitazione: non conosce i nostri dati privati. Come possiamo costruirci un nostro assistente virtuale, o meglio un chabot, che usi i nostri dati e che non ci richieda investimenti di denaro? Scopriamo come costruirne uno usando LLM open, ambienti computazionali gratuiti come Colab e librerie Python per gestire file PDF e creare interfacce web semplici ed intuitive.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Design with MongoDB

Design with MongoDB!!!

Buy the new book that will help you to use MongoDB correctly for your applications. Available now on Amazon!