In breve: No, le tue VOLUME
istruzioni non sono corrette.
I file Docker VOLUME
specificano uno o più volumi dati percorsi lato contenitore. Ma non consente all'autore dell'immagine di specificare un percorso host. Sul lato host, i volumi vengono creati con un nome simile a ID molto lungo all'interno della radice Docker. Sulla mia macchina questo è /var/lib/docker/volumes
.
Nota: poiché il nome generato automaticamente è estremamente lungo e non ha senso dal punto di vista di un essere umano, questi volumi sono spesso definiti "senza nome" o "anonimi".
Il tuo esempio che utilizza un '.' il personaggio non funzionerà nemmeno sulla mia macchina, non importa se faccio del punto il primo o il secondo argomento. Ricevo questo messaggio di errore:
finestra mobile: Risposta di errore dal demone: errore di runtime oci: container_linux.go: 265: l'avvio del processo del contenitore ha causato "process_linux.go: 368: init contenitore ha causato \" open / dev / ptmx: nessun file o directory \ "".
So che ciò che è stato detto fino a questo punto probabilmente non è molto prezioso per qualcuno che cerca di capire VOLUME
e -v
certamente non fornisce una soluzione per ciò che si tenta di realizzare. Quindi, si spera, i seguenti esempi faranno ancora più luce su questi problemi.
Minitutorial: specificare i volumi
Dato questo Dockerfile:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Per il risultato di questo minitutivo, non fa alcuna differenza se specifichiamo vol1 vol2
o /vol1 /vol2
- non chiedetemi perché)
Costruiscilo:
docker build -t my-openjdk
Correre:
docker run --rm -it my-openjdk
All'interno del contenitore, esegui ls
dalla riga di comando e noterai che esistono due directory; /vol1
e /vol2
.
L'esecuzione del contenitore crea anche due directory, o "volumi", sul lato host.
Mentre il contenitore è in esecuzione, eseguilo docker volume ls
sul computer host e vedrai qualcosa del genere (per brevità ho sostituito la parte centrale del nome con tre punti):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
Torna nel contenitore , esegui touch /vol1/weird-ass-file
(crea un file vuoto in detta posizione).
Questo file è ora disponibile sul computer host, in uno dei volumi senza nome lol. Mi ci sono voluti due tentativi perché ho provato prima il primo volume elencato, ma alla fine ho trovato il mio file nel secondo volume elencato, usando questo comando sul computer host:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
Allo stesso modo, puoi provare a eliminare questo file sull'host e verrà eliminato anche nel contenitore.
Nota: la _data
cartella viene anche definita "punto di montaggio".
Esci dal contenitore ed elenca i volumi sull'host. Se ne sono andati. Abbiamo utilizzato il --rm
flag durante l'esecuzione del contenitore e questa opzione cancella efficacemente non solo il contenitore all'uscita, ma anche i volumi.
Esegui un nuovo contenitore, ma specifica un volume usando -v
:
docker run --rm -it -v /vol3 my-openjdk
Questo aggiunge un terzo volume e l'intero sistema finisce per avere tre volumi senza nome. Il comando si sarebbe arrestato in modo anomalo se avessimo specificato solo -v vol3
. L'argomento deve essere un percorso assoluto all'interno del contenitore. Sul lato host, il nuovo terzo volume è anonimo e risiede insieme agli altri due volumi in /var/lib/docker/volumes/
.
In precedenza era stato affermato che Dockerfile
non è possibile eseguire il mapping a un percorso host che può rappresentare un problema per noi quando si tenta di portare i file dall'host al contenitore durante il runtime. Una -v
sintassi diversa risolve questo problema.
Immagina di avere una sottocartella nella directory del mio progetto ./src
che desidero sincronizzare /src
all'interno del contenitore. Questo comando fa il trucco:
docker run -it -v $(pwd)/src:/src my-openjdk
Entrambi i lati del :
personaggio si aspettano un percorso assoluto. Il lato sinistro è un percorso assoluto sulla macchina host, il lato destro è un percorso assoluto all'interno del contenitore. pwd
è un comando che "stampa la directory corrente / di lavoro". Inserire il comando $()
prende il comando tra parentesi, lo esegue in una subshell e restituisce il percorso assoluto alla nostra directory di progetto.
Mettendo tutto insieme, supponiamo che abbiamo ./src/Hello.java
nella nostra cartella del progetto sul computer host con i seguenti contenuti:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
Costruiamo questo Dockerfile:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
Eseguiamo questo comando:
docker run -v $(pwd)/src:/src my-openjdk
Questo stampa "Ciao, mondo!".
La parte migliore è che siamo completamente liberi di modificare il file .java con un nuovo messaggio per un altro output in una seconda esecuzione - senza dover ricostruire l'immagine =)
Osservazioni finali
Sono abbastanza nuovo su Docker e il summenzionato "tutorial" riflette le informazioni che ho raccolto da un hackathon della riga di comando di 3 giorni. Mi vergogno quasi di non essere stato in grado di fornire collegamenti a una chiara documentazione di tipo inglese a supporto delle mie dichiarazioni, ma sinceramente penso che ciò sia dovuto alla mancanza di documentazione e non allo sforzo personale. So che gli esempi funzionano come pubblicizzato usando la mia configurazione attuale che è "Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce".
Il tutorial non risolve il problema "come possiamo specificare il percorso del container nel Dockerfile e lasciare che il comando run specifichi solo il percorso host". Potrebbe esserci un modo, semplicemente non l'ho trovato.
Infine, ho la sensazione che specificare VOLUME
nel Dockerfile non sia solo raro, ma è probabilmente una buona pratica da non usare mai VOLUME
. Per due motivi. Il primo motivo che abbiamo già identificato: non è possibile specificare il percorso host, il che è positivo perché i file Docker dovrebbero essere molto agnostici rispetto alle specifiche di una macchina host. Ma il secondo motivo è che le persone potrebbero dimenticare di utilizzare l' --rm
opzione durante l'esecuzione del contenitore. Si potrebbe ricordare di rimuovere il contenitore ma dimenticare di rimuovere il volume. Inoltre, anche con il meglio della memoria umana, potrebbe essere un compito scoraggiante capire quale di tutti i volumi anonimi è sicuro da rimuovere.