Volumi Docker e montaggi di associazione: mantenere i dati del contenitore nel modo giusto

  1. Home
  2. Blog
  3. DevOps

DevOps

Volumi Docker e montaggi di associazione: Perseverare i dati del contenitore nel modo giusto

Rimuovi un contenitore e con esso i suoi dati, a meno che non lo conservi in un posto più sicuro. Scopri la differenza tra volumi, bind mount e tmpfs, quando utilizzarli e come eseguire il backup di ciò che conta.

9 min di lettura
Volumi Docker e montaggi di associazione: persistenza dei dati del contenitore nel modo giusto

Punti chiave

  • Il livello scrivibile di un contenitore viene eliminato insieme al contenitore, quindi i dati importanti necessitano di un montaggio.
  • I volumi con nome sono gestiti da Docker e sono la scelta abituale per database e dati di produzione.
  • I supporti di associazione mappano una cartella host, il che li rende ideali per il codice live durante lo sviluppo.
  • docker compose down -v elimina i volumi, quindi usalo con cura e conserva i backup testati.

Avvia un database in un contenitore, aggiungi alcuni dati, rimuovi il contenitore e ne avvii uno nuovo. I dati sono spariti. Quasi tutti imparano questa lezione nel modo più duro. I volumi Docker e i montaggi di bind esistono per mantenere i dati in vita oltre la vita di qualsiasi contenitore.

Questa guida spiega come funziona ciascuno e come scegliere. I comandi e i file qui sono esempi standard, basati sul comportamento documentato di Docker e non li abbiamo eseguiti per questo articolo, quindi provali prima su dati usa e getta. I dettagli possono differire tra le versioni di Docker e su Docker Desktop. Se non conosci i container, inizia con il nostro tutorial su Docker per principianti.

Perché i dati contenitore scompaiono

Un’immagine Docker è composta da livelli di sola lettura. Quando si avvia un contenitore, Docker aggiunge un sottile livello scrivibile sopra e tutte le modifiche vengono inserite lì. Tale livello sopravvive all’arresto e al riavvio, ma viene rimosso quando il contenitore viene eliminato.

docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# ... create tables and add data ...
docker rm -f db
docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# The data you added is not there

Questo è previsto dalla progettazione, poiché consente di sostituire liberamente i contenitori. Significa che tutto ciò che devi conservare deve vivere fuori dal contenitore. Ci sono tre modi per farlo:

Digitare Memorizzato in Sopravvive alla rimozione del contenitore?
Volume denominato Un’area gestita da Docker Sì
Legare il supporto Un percorso host scelto da te Sì
montaggio tmpfs Memoria dell’ospite No

Volumi Docker e montaggi di collegamento affiancati

Aspetto Volume denominato Legare il supporto
Gestito da Docker Tu
Posizione Area di archiviazione di Docker Qualsiasi percorso sull’host
Dipende dalle cartelle host? No Sì
Modifica dall’host Imbarazzante per progettazione Facile, le modifiche appaiono istantaneamente
Target vuoto precompilato dall’immagine? Sì No, il percorso host lo nasconde
Comandi della CLI Docker Sì, docker volume No
Driver per l’archiviazione remota Sì No
Meglio per Database, dati di produzione Codice sorgente in sviluppo

Volumi con nome

Un volume è uno spazio di archiviazione creato e gestito da Docker. Ti riferisci ad esso per nome e non devi preoccuparti di dove vive fisicamente.

docker volume create pgdata

docker run -d --name db \
  -e POSTGRES_PASSWORD=devonly \
  -v pgdata:/var/lib/postgresql/data \
  postgres:17

Ora i file del database risiedono in pgdata. Elimina il contenitore e avviane uno nuovo con lo stesso volume e i tuoi dati saranno ancora lì. Su Linux, i volumi di solito si trovano sotto /var/lib/docker/volumes/, ma non dovresti modificare direttamente quei file. Su Docker Desktop risiedono all’interno di una macchina virtuale, non in una normale cartella.

Il percorso all’interno del contenitore dipende dall’immagine, quindi controlla la documentazione dell’immagine. Montare sul percorso sbagliato è un classico errore: tutto sembra funzionare, ma i dati vengono ancora scritti nel livello contenitore. Anche le versioni principali più recenti di un’immagine possono modificare questo percorso, quindi leggere le note sulla versione prima dell’aggiornamento.

Docker creerà automaticamente un volume denominato se non esiste. Funziona anche un volume anonimo, creato senza nome, ma ottiene un ID casuale lungo ed è facile perderne traccia. Assegna sempre nomi ai tuoi volumi.

Legare i supporti

Un montaggio di associazione mappa un percorso host specifico direttamente nel contenitore. Entrambe le parti vedono immediatamente gli stessi file. Ciò lo rende perfetto per lo sviluppo, poiché le modifiche nel tuo editor hanno effetto nel contenitore in esecuzione senza una ricostruzione:

docker run -d --name web \
  -p 8080:80 \
  -v "$(pwd)/site:/usr/share/nginx/html:ro" \
  nginx:1.27

Modifica un file in site/, aggiorna il browser e vedrai la modifica. Il :ro rende il montaggio di sola lettura all’interno del contenitore, il che è una buona abitudine quando il contenitore non ha bisogno di scrivere lì.

I supporti di rilegatura presentano alcuni compromessi:

  • Ti legano all’host. Il percorso deve esistere su ogni macchina, quindi le configurazioni sono meno portabili.
  • Nascondono il contenuto dell’immagine. Se monti sopra /app, qualunque cosa contenesse l’immagine diventa invisibile. Un esempio comune è la scomparsa di node_modules.
  • Espongono l’host. Un contenitore con un montaggio scrivibile può modificare o eliminare file host reali. Non montare mai percorsi sensibili come / o il socket Docker a meno che non si comprenda appieno il rischio.
  • Le prestazioni possono variare. Su Docker Desktop per macOS e Windows, la condivisione dei file supera i limiti della virtualizzazione e può essere più lenta rispetto a Linux.

tmpfs si monta

Un montaggio tmpfs risiede nella memoria dell’host e non viene mai scritto nel livello contenitore. Svanisce quando il contenitore si ferma, quindi è adatto a file temporanei, cache e dati sensibili di breve durata:

docker run -d --tmpfs /app/cache:size=64m myapp:1.0

tmpfs è disponibile sugli host Linux. Può anche velocizzare i database in ambienti di test usa e getta, dove non ti interessa conservare i dati.

-v o –mount?

Entrambi i flag funzionano. --mount è più lungo, ma è più esplicito e molte persone lo preferiscono negli script:

# Short form
docker run -v pgdata:/var/lib/postgresql/data postgres:17

# Explicit form
docker run --mount type=volume,source=pgdata,target=/var/lib/postgresql/data postgres:17

# Bind mount, read-only
docker run --mount type=bind,source="$(pwd)"/site,target=/usr/share/nginx/html,readonly nginx:1.27

C’è una differenza significativa. Con -v, viene creato un percorso host mancante come cartella vuota, che può nascondere un errore di battitura. Con --mount e un tipo di associazione, Docker segnala invece un errore. Inoltre, con -v, il lato sinistro decide il tipo: un nome significa un volume e un percorso significa un mount di collegamento. Quindi -v data:/x e -v ./data:/x fanno cose molto diverse.

Volumi in Docker Compose

La maggior parte dei progetti reali dichiara l’archiviazione in un file Compose. Questo utilizza entrambi i tipi, ciascuno per il proprio lavoro:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src      # bind mount: live code
    depends_on:
      - db

  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: devonly
    volumes:
      - pgdata:/var/lib/postgresql/data   # named volume: data

volumes:
  pgdata:

I volumi denominati devono essere dichiarati nella sezione di livello superiore volumes. Compose antepone il nome effettivo al nome del progetto. Consulta il nostro tutorial su Docker Compose per una procedura dettagliata completa.

Suggerimento: docker compose down mantiene i volumi con nome, ma docker compose down -v li elimina, insieme ai tuoi dati. Prestare particolare attenzione agli script e alla cronologia della shell che includono -v.

Comandi utili per il volume

Comando Cosa fa
volume della finestra mobile ls Elenca i volumi
nome di creazione del volume della finestra mobile Crea un volume
nome dell'ispezione del volume della finestra mobile Mostra i dettagli, inclusa la sua posizione
nome rm del volume della finestra mobile Elimina un volume e i relativi dati
potatura del volume della finestra mobile Rimuove i volumi non utilizzati
sistema docker df -v Mostra l’utilizzo del disco, inclusi i volumi

Controlla cosa prune rimuoverà prima di confermarlo, poiché questa operazione non può essere annullata. I volumi che nessun contenitore attualmente utilizza potrebbero comunque contenere dati importanti.

Eseguire il backup e ripristinare un volume

È possibile eseguire il backup di un volume eseguendo un contenitore di breve durata che monta sia il volume che una cartella host:

# Back up
docker run --rm \
  -v pgdata:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

# Restore into a new volume
docker volume create pgdata_restored
docker run --rm \
  -v pgdata_restored:/data \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

Per un database attivo, la copia di file come questo può acquisire uno stato incoerente. Arrestare prima il contenitore o, meglio, utilizzare lo strumento del database, come pg_dump per PostgreSQL. E un backup che non hai mai ripristinato è in realtà solo una speranza, quindi prova il ripristino.

Autorizzazioni sui file

“Permesso negato” è il problema più comune con i mount. I file mantengono gli ID utente e gruppo numerici su Linux, quindi se un contenitore viene eseguito come utente 1000 e la cartella host appartiene a un altro utente, le scritture falliranno. Alcuni modi per risolvere questo problema:

  • Esegui il contenitore con un utente corrispondente: docker run --user "$(id -u):$(id -g)" ...
  • Imposta la proprietà corretta della tua immagine, come descritto nelle nostre best practice per Dockerfile.
  • Preferire i volumi denominati per i dati, poiché un nuovo volume assume la proprietà della cartella dell’immagine quando viene utilizzato per la prima volta.
  • Sui sistemi che utilizzano SELinux, i montaggi di collegamento potrebbero richiedere un’etichetta :z o :Z.

Evita la tentazione di chmod 777, come spiega la nostra guida ai comandi Linux.

Quale dovresti usare?

Situazione Utilizzare
Dati della banca dati Volume denominato
Codice sorgente con modifica in tempo reale Legare il supporto
Un file di configurazione dal tuo repository Montaggio di associazione di sola lettura
Condivisione dei dati tra contenitori Volume denominato
Cache temporanea o file di lavoro tmpfs
Database dei test usa e getta tmpfs o nessun montaggio
Codice dell’applicazione in produzione Costruiscilo nell’immagine

L’ultima riga è importante. In produzione, il codice appartiene all’immagine, in modo che ciò che hai testato sia ciò che esegui. Nei cluster, l’archiviazione dei dati funziona ancora in modo diverso, attraverso volumi persistenti, che sono trattati nella documentazione più ampia di Kubernetes. La nostra guida Docker vs Kubernetes spiega come i due si relazionano.

Errori comuni

  • Montaggio sul percorso sbagliato. I dati risiedono ancora nel livello contenitore e scompaiono in seguito.
  • Esecuzione down -v casualmente. Questa operazione elimina i volumi con nome.
  • Utilizzo di percorsi relativi con -v. Moduli come -v data:/x creano un volume anziché una mappatura di cartelle.
  • Inserire i segreti in supporti di associazione scrivibili. Montarli in sola lettura o utilizzare una funzionalità dei segreti.
  • Puntare due contenitori di database su un volume. Ciò può danneggiare i dati.
  • Non sono presenti backup. Un volume non è un backup. Vive sullo stesso disco.

Considerazioni finali

La regola pratica è breve: volumi denominati per i dati, montaggi di associazione per il codice che stai modificando e tmpfs per cose che non dovrebbero durare. Provalo su un database usa e getta. Crea un volume denominato, aggiungi una riga, elimina il contenitore, iniziane uno nuovo e conferma che la riga è sopravvissuta. Quindi esercitati con un backup e un ripristino prima di averne bisogno.

Domande frequenti

Qual è la differenza tra un volume Docker e un montaggio di associazione?

Un volume viene gestito da Docker e archiviato nella propria area. Un montaggio di associazione mappa un percorso host specifico che controlli, direttamente nel contenitore.

L’arresto di un contenitore ne cancella i dati?

No. I dati nel livello scrivibile sopravvivono all’arresto e al riavvio. Viene perso quando il contenitore viene rimosso, a meno che non sia archiviato in un volume o in un montaggio di associazione.

I volumi Docker persistono dopo la composizione del docker?

Sì, i volumi denominati rimangono dopo la composizione della finestra mobile. L’aggiunta del flag -v li elimina, insieme a tutti i dati in essi contenuti.

Dove sono archiviati i volumi Docker?

Su Linux, solitamente in /var/lib/docker/volumes. Su Docker Desktop risiedono all’interno di una macchina virtuale. Utilizzare l’ispezione del volume della finestra mobile per visualizzare la posizione.

Più contenitori possono condividere un volume?

Sì, più contenitori possono montare un volume. L’applicazione deve gestire l’accesso simultaneo in modo sicuro e in genere i database non dovrebbero condividere file di dati in questo modo.

Continua a imparare

Lavora con Stack Quora

Hai bisogno di aiuto con test, WordPress o SEO?

Aiutiamo i team a fornire software migliore e a far crescere i loro siti. Raccontaci a cosa stai lavorando e ti suggeriremo chiaramente il prossimo passo.

Continua a leggere

Altre guide su test, intelligenza artificiale e sviluppo moderno

Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.

Intelligenza artificiale

Spiegazione delle allucinazioni dell'intelligenza artificiale: perché i modelli linguistici inventano le cose e come ridurle

Spiegazione delle allucinazioni dell'intelligenza artificiale: cosa sono, perché i modelli linguistici le producono, tipi comuni, come ridurle con b…

Leggi l'articolo →
DevOps

Spiegazione delle variabili d'ambiente: file .env, segreti e configurazione eseguiti correttamente

Variabili d'ambiente spiegate con esempi Python che abbiamo eseguito: lettura e impostazione, perché ogni valore è una stringa, file .env, ereditari…

Leggi l'articolo →
Sviluppo software

Spiegazione della limitazione della velocità API: algoritmi, intestazioni e gestione degli errori 429

La limitazione della velocità dell'API spiegata con una simulazione che abbiamo eseguito: bucket di token, finestra fissa, finestra scorrevole, risp…

Leggi l'articolo →
Automazione dei test

Derisione in Python: unittest.mock, patch e gli errori che fanno mentire i test

Mocking in Python con unittest.mock, testato: Mock e return_value, side_effect, patch dove viene utilizzato un nome, specifiche e autospec, date moc…

Leggi l'articolo →
Test del software

Spiegazione della copertura del codice: copertura di linea o di filiale e cosa significa realmente il 100%.

Copertura del codice spiegata con una vera esecuzione di cover.py: copertura di linea, ramo e condizione, lettura di un rapporto, perché la copertur…

Leggi l'articolo →
Database e SQL

DELETE vs TRUNCATE vs DROP in SQL: differenze, rollback e quando utilizzarli

DELETE vs TRUNCATE vs DROP spiegato con SQL testato: cosa rimuove, rollback, trigger, reimpostazione dell'identità, velocità e come differiscono Pos…

Leggi l'articolo →
Database e SQL

Spiegazione delle visualizzazioni SQL: crea, utilizza ed evita le insidie, con esempi

Viste SQL spiegate con le query che abbiamo eseguito: creazione di una vista, risultati in tempo reale, nascondere colonne, prestazioni, viste aggio…

Leggi l'articolo →
Sviluppo software

Interfaccia TypeScript e tipo: differenze reali, testate con il compilatore

Interfaccia TypeScript vs tipo, verificata con il vero compilatore: cosa possono fare entrambi, cosa può fare solo uno, fusione delle dichiarazioni,…

Leggi l'articolo →
Sviluppo software

Spiegazione di Python *args e **kwargs: funzioni flessibili con esempi chiari

Python *args e **kwargs spiegati con il codice che abbiamo eseguito: compressione e decompressione, ordine dei parametri, argomenti solo per parole …

Leggi l'articolo →
Sviluppo software

Funzioni Lambda Python: sintassi, usi reali e quando non usarli

Funzioni lambda Python spiegate con il codice che abbiamo eseguito: sintassi, ordinamento con chiave, mappa e filtro, chiusure, trap dell'associazio…

Leggi l'articolo →
Intelligenza artificiale

Cosa sono gli agenti AI? Come funzionano, con un semplice ciclo di agenti che puoi eseguire

Cosa sono gli agenti IA? Una semplice guida al ciclo dell'agente, agli strumenti, alla memoria e ai guardrail, con un piccolo ciclo Python che abbia…

Leggi l'articolo →
DevOps

Monitoraggio vs osservabilità: la vera differenza, con log, metriche e tracce

Spiegazione del monitoraggio e dell'osservabilità: errori noti e sconosciuti, log, metriche e tracce, una procedura dettagliata sugli incidenti di p…

Leggi l'articolo →
DevOps

Volumi Docker e montaggi di associazione: mantenere i dati del contenitore nel modo giusto

Volumi Docker e montaggi di collegamento spiegati: perché i dati del contenitore scompaiono, volumi denominati, montaggi di collegamento, tmpfs, ese…

Leggi l'articolo →
Automazione dei test

TDD vs BDD: differenze chiave, una caratteristica costruita in entrambi i modi e quando utilizzarli ciascuno

TDD vs BDD spiegato con una funzione di sconto costruita in entrambi i modi: refactoring rosso-verde con il codice che abbiamo eseguito, scenari "Da…

Leggi l'articolo →
Sviluppo software

Git merge vs rebase: differenze, esempi e quando usare ciascuno

Git merge vs rebase spiegato con output reale del log, una tabella di confronto, la regola d'oro del rebase e un flusso di lavoro sicuro per i team.

Leggi l'articolo →
Sviluppo software

List comprehension in Python: sintassi, esempi e quando evitarla

List comprehension in Python spiegata: sintassi, filtri, if-else, cicli annidati, tempi misurati e i casi in cui un normale ciclo for è meglio.

Leggi l'articolo →
Database e SQL

SQL JOIN spiegati con esempi (Inner, Left, Right, Full)

Capisci i JOIN SQL passo dopo passo con tabelle e query di esempio: INNER, LEFT, RIGHT, FULL, CROSS e SELF, con errori comuni e consigli sulle prest…

Leggi l'articolo →