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.
- 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 -velimina 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 dinode_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
:zo: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 -vcasualmente. Questa operazione elimina i volumi con nome. - Utilizzo di percorsi relativi con
-v. Moduli come-v data:/xcreano 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
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.
Altre guide su test, intelligenza artificiale e sviluppo moderno
Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.
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 →DevOpsSpiegazione 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 softwareSpiegazione 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 testDerisione 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 softwareSpiegazione 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 SQLDELETE 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 SQLSpiegazione 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 softwareInterfaccia 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 softwareSpiegazione 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 softwareFunzioni 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 artificialeCosa 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 →DevOpsMonitoraggio 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 →DevOpsVolumi 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 testTDD 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 softwareGit 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 softwareList 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 SQLSQL 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 →