En bref: non, votre VOLUME
instruction n'est pas correcte.
Les fichiers Dockerfile VOLUME
spécifient un ou plusieurs volumes en fonction des chemins côté conteneur. Mais cela ne permet pas à l'auteur de l'image de spécifier un chemin d'hôte. Du côté de l'hôte, les volumes sont créés avec un nom de type ID très long à l'intérieur de la racine Docker. Sur ma machine, c'est /var/lib/docker/volumes
.
Remarque: étant donné que le nom généré automatiquement est extrêmement long et n'a aucun sens du point de vue d'un humain, ces volumes sont souvent appelés «sans nom» ou «anonymes».
Votre exemple qui utilise un "." caractère ne fonctionnera même pas sur ma machine, peu importe si je fais du point le premier ou le deuxième argument. Je reçois ce message d'erreur:
docker: réponse d'erreur du démon: erreur d'exécution oci: container_linux.go: 265: démarrage du processus de conteneur causé "process_linux.go: 368: conteneur init causé \" open / dev / ptmx: aucun fichier ou répertoire de ce type \ "".
Je sais que ce qui a été dit à ce point est sans doute pas très utile pour quelqu'un qui essaie de comprendre VOLUME
et -v
et il ne est certainement pas à une solution pour ce que vous essayez d'accomplir. Nous espérons donc que les exemples suivants éclaireront davantage ces questions.
Minitutorial: Spécification des volumes
Compte tenu de ce Dockerfile:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Pour le résultat de ce minitutoriel, cela ne fait aucune différence si nous spécifions vol1 vol2
ou /vol1 /vol2
- ne me demandez pas pourquoi)
Construit le:
docker build -t my-openjdk
Courir:
docker run --rm -it my-openjdk
À l'intérieur du conteneur, exécutez ls
la ligne de commande et vous remarquerez que deux répertoires existent; /vol1
et /vol2
.
L'exécution du conteneur crée également deux répertoires, ou "volumes", du côté hôte.
Pendant que le conteneur est en cours d'exécution, exécutez docker volume ls
sur la machine hôte et vous verrez quelque chose comme ceci (j'ai remplacé la partie centrale du nom par trois points par souci de concision):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
De retour dans le conteneur , exécutez touch /vol1/weird-ass-file
(crée un fichier vierge à cet emplacement).
Ce fichier est maintenant disponible sur la machine hôte, dans l'un des volumes sans nom lol. Cela m'a pris deux essais car j'ai d'abord essayé le premier volume répertorié, mais j'ai finalement trouvé mon fichier dans le deuxième volume répertorié, en utilisant cette commande sur la machine hôte:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
De même, vous pouvez essayer de supprimer ce fichier sur l'hôte et il sera également supprimé dans le conteneur.
Remarque: Le _data
dossier est également appelé "point de montage".
Quittez le conteneur et répertoriez les volumes sur l'hôte. Ils sont partis. Nous avons utilisé l' --rm
indicateur lors de l'exécution du conteneur et cette option efface efficacement non seulement le conteneur à la sortie, mais également les volumes.
Exécutez un nouveau conteneur, mais spécifiez un volume en utilisant -v
:
docker run --rm -it -v /vol3 my-openjdk
Cela ajoute un troisième volume et l'ensemble du système finit par avoir trois volumes sans nom. La commande se serait plantée si nous l'avions spécifié seulement -v vol3
. L'argument doit être un chemin absolu à l' intérieur du conteneur. Du côté hôte, le nouveau troisième volume est anonyme et réside avec les deux autres volumes dans /var/lib/docker/volumes/
.
Il a été indiqué précédemment que le Dockerfile
ne peut pas être mappé à un chemin d'hôte, ce qui pose un problème pour nous lorsque nous essayons d'apporter des fichiers de l'hôte au conteneur pendant l'exécution. Une -v
syntaxe différente résout ce problème.
Imaginez que j'ai un sous-dossier dans le répertoire de mon projet ./src
que je souhaite synchroniser à l' /src
intérieur du conteneur. Cette commande fait l'affaire:
docker run -it -v $(pwd)/src:/src my-openjdk
Les deux côtés du :
personnage attendent un chemin absolu. Le côté gauche étant un chemin absolu sur la machine hôte, le côté droit étant un chemin absolu à l'intérieur du conteneur. pwd
est une commande qui "imprime le répertoire courant / de travail". Mettre la commande dans $()
prend la commande entre parenthèses, l'exécute dans un sous-shell et renvoie le chemin absolu vers notre répertoire de projet.
En mettant tout cela ensemble, supposons que nous avons ./src/Hello.java
dans notre dossier de projet sur la machine hôte avec le contenu suivant:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
Nous construisons ce Dockerfile:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
Nous exécutons cette commande:
docker run -v $(pwd)/src:/src my-openjdk
Cela imprime "Hello, World!".
La meilleure partie est que nous sommes totalement libres de modifier le fichier .java avec un nouveau message pour une autre sortie lors d'une deuxième exécution - sans avoir à reconstruire l'image =)
Remarques finales
Je suis assez nouveau dans Docker, et le "tutoriel" mentionné ci-dessus reflète les informations que j'ai recueillies à partir d'un hackathon en ligne de commande de 3 jours. J'ai presque honte de ne pas avoir été en mesure de fournir des liens vers une documentation claire de type anglais pour étayer mes déclarations, mais je pense honnêtement que cela est dû à un manque de documentation et non à un effort personnel. Je sais que les exemples fonctionnent comme annoncé en utilisant ma configuration actuelle qui est "Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce".
Le tutoriel ne résout pas le problème "comment spécifier le chemin du conteneur dans le Dockerfile et laisser la commande run spécifier uniquement le chemin de l'hôte". Il y a peut-être un moyen, je ne l'ai tout simplement pas trouvé.
Enfin, j'ai le sentiment instinctif que la spécification VOLUME
dans le Dockerfile n'est pas seulement rare, mais c'est probablement une meilleure pratique à ne jamais utiliser VOLUME
. Pour deux raisons. La première raison que nous avons déjà identifiée: nous ne pouvons pas spécifier le chemin de l'hôte - ce qui est une bonne chose car Dockerfiles doit être très indépendant des spécificités d'une machine hôte. Mais la deuxième raison est que les gens peuvent oublier d'utiliser l' --rm
option lors de l'exécution du conteneur. On peut se rappeler de retirer le conteneur mais oublier de retirer le volume. De plus, même avec le meilleur de la mémoire humaine, il peut être difficile de déterminer quels volumes anonymes peuvent être supprimés en toute sécurité.