Salta al contenuto principale

Orvieto Linux User Group | Promozione software libero a Orvieto

Volumi Docker: guida alla persistenza dei dati dei container

docker-logo-ocean-blue

Se sei alle prime armi con Docker, ti consigliamo di partire dalla nostra introduzione a Docker su Linux, dove abbiamo visto cosa sono immagini e container e come utilizzare i primi comandi. 
Se invece hai già esperienza con i container… partiamo!

Dati persistenti e container: perché i volumi sono importanti

Uno dei concetti più interessanti di Docker è anche uno dei primi problemi che si incontrano quando si passa dai semplici test a un utilizzo reale dei container. 

Un container può essere creato, avviato, fermato e infine eliminato. Ma cosa succede ai dati che abbiamo creato all’interno del container?

Immaginiamo, ad esempio, di avviare un database in Docker.

Il database contiene:

  • configurazioni;
  • utenti;
  • tabelle;
  • documenti;
  • dati dell’applicazione.

Se tutti questi dati vengono memorizzati esclusivamente all’interno del filesystem scrivibile del container, eliminando il container rischiamo di perdere anche i dati.

È proprio qui che entrano in gioco i volumi Docker.

Un volume permette di separare il ciclo di vita dei dati da quello del container che li utilizza.

In altre parole:

Il container può essere eliminato e ricreato, mentre i dati rimangono disponibili.

È uno dei passaggi fondamentali per iniziare a utilizzare Docker non soltanto per fare prove, ma anche per eseguire servizi persistenti.


Cosa succede ai dati dentro un container?

Per capire perché esistono i volumi, dobbiamo prima capire come Docker gestisce il filesystem di un container.

Quando Docker avvia un container, parte dall’immagine utilizzata per crearlo. L’immagine contiene i filesystem layer necessari all’applicazione, mentre il container dispone anche di un proprio writable layer, cioè un livello scrivibile associato a quel particolare container.

Possiamo immaginarlo in questo modo:

             IMMAGINE DOCKER
          ┌──────────────────┐
          │  filesystem      │
          │  applicazione    │
          │  librerie        │
          └────────┬─────────┘
                   │
                   ▼
          ┌──────────────────┐
          │ Writable layer   │
          │ del container    │
          └──────────────────┘
                   │
                   ▼
              CONTAINER

Quando un’applicazione scrive un file, normalmente quel file finisce nel writable layer del container.

Il problema è che questo livello è legato al container.

Se il container viene eliminato, anche quel livello viene eliminato.

Docker stessa evidenzia proprio questa caratteristica: i dati scritti nel writable layer non sono pensati per sopravvivere alla distruzione del container.


Facciamo una prova pratica

Possiamo vedere il comportamento direttamente.

Creiamo un semplice container:

docker run -it --name test-dati ubuntu:24.04 bash

Una volta entrati nel container creiamo un file denominato dati.txt al suo interno, con una frase salvata come contenuto:

echo "Questo dato è dentro il container" > /dati.txt

Potremo quindi verificare con questo comando:

cat /dati.txt

che il file esiste, se otterremo la frase inserita con echo.
Se ora usciamo lanciando il comando “exit”, il container non sarà più in esecuzione ma esisterà ancora; potremo verificare questo tramite il seguente comando:

docker ps

e riavviandolo con:

docker start -ai test-dati

noteremo che il file sarà ancora presente nel container! Questo è normale: fermare un container non significa eliminarlo.

Ma lanciando il seguente comando:

docker rm test-dati

a questo punto il container non esisterà più fisicamente.

Se, quindi, ricreiamo il container:

docker run -it --name test-dati ubuntu:24.04 bash

e proviamo a lanciare le seguenti operazioni in sequenza:

cat /dati.txt

otterremo come risposta: “cat: /dati.txt: No such file or directory”!
Ovviamente il dato è scomparso perché era contenuto nel filesystem del vecchio container e disponibile nel nuovo container, perché era contenuto nel filesystem scrivibile del vecchio container, che è stato eliminato insieme al container.

Per evitare tuttavia queste situazioni fortunatamente ci danno una mano i volumi Docker!

Che cos’è un volume Docker?

Un volume è uno spazio di archiviazione gestito direttamente da Docker e separato dal filesystem del container.

Possiamo immaginarlo così:

                  HOST LINUX
                      │
        ┌─────────────┴─────────────┐
        │                           │
        ▼                           ▼
   CONTAINER                    VOLUME
┌───────────────┐          ┌───────────────┐
│ Applicazione  │          │ Dati          │
│               │◄────────►│ persistenti   │
│ /app/data     │          │               │
└───────────────┘          └───────────────┘

Il container vede il volume semplicemente come una directory.

Ad esempio /data: per l’applicazione quella directory appare come una normale cartella del filesystem del container, ma i dati vengono conservati nel volume gestito da Docker

La caratteristica fondamentale è che il volume non viene eliminato automaticamente insieme al container.
Il suo ciclo di vita è indipendente da quello del container.


Creare il primo volume

Creare un volume è molto semplice:

docker volume create dati-app

Possiamo verificare che esista con:

docker volume ls

Dovremmo vedere qualcosa come:

DRIVER    VOLUME NAME
local     dati-app

Docker mostrerà informazioni relative al volume, compreso il driver utilizzato e il percorso gestito dal Docker Engine.

È importante però una cosa:

Non è necessario entrare manualmente nella directory interna del volume sul filesystem dell’host.

Docker gestisce quella posizione e la documentazione raccomanda di interagire con i dati del volume attraverso il volume stesso e i container che lo montano, anziché manipolarne direttamente i file sul filesystem dell’host.


Utilizzare un volume con un container

Ora possiamo utilizzare il volume appena creato.

Creiamo un container Ubuntu:

docker run -it \
  --name test-volume \
  --mount type=volume,src=dati-app,dst=/data \
  ubuntu:24.04 \
  bash

All’interno del container possiamo controllare:

ls /data

Inizialmente la directory sarà vuota. Creiamo un file:

echo "Dato persistente" > /data/messaggio.txt

e verifichiamo:

cat /data/messaggio.txt

Dovremmo ottenere: “Dato persistente” come output! 
Usciamo quindi con il comando “exit” e rimuoviamo il container:

docker rm test-volume

Il container è stato eliminato, il volume invece esiste ancora. Possiamo verificarlo così:

docker volume ls

e troveremo:

local     dati-app

Prova del 9: ricreare il container e ritrovare i dati

Creiamo un nuovo container utilizzando lo stesso volume:

docker run -it \
  --name test-volume-2 \
  --mount type=volume,src=dati-app,dst=/data \
  ubuntu:24.04 \
  bash

Ora:

cat /data/messaggio.txt

restituirà:

Dato persistente

Abbiamo appena dimostrato il principio fondamentale dei volumi:

CONTAINER 1
    │
    │ scrive
    ▼
┌──────────────┐
│ dati-app     │
└──────────────┘
    ▲
    │ legge
    │
CONTAINER 2

Il primo container è stato eliminato ma il volume no; il secondo container ha quindi potuto ritrovare gli stessi dati.

Conclusioni

I container Docker sono progettati per essere facilmente creati, fermati, sostituiti e ricreati.

Questa caratteristica è uno dei loro punti di forza, ma introduce una domanda fondamentale:

Dove mettiamo i dati che devono sopravvivere al container?

La risposta, nella maggior parte dei casi, è un volume Docker.

LICENZA E CONDIZIONI D’USO

Questo How-to è rilasciato sotto licenza Creative Commons Attribution-NonCommercial 3.0 Italy

CONTATTI DELL’AUTORE

Marco Ciammella marco@orvietolinux.it

Orvieto Linux User Group info@orvietolinux.it