192 votes

Comprendre l’instruction "VOLUME" dans DockerFile

Ci-dessous le contenu de mon "Dockerfile"

 FROM node:boron

# Create app directory
RUN mkdir -p /usr/src/app

# change working dir to /usr/src/app
WORKDIR /usr/src/app

VOLUME . /usr/src/app

RUN npm install

EXPOSE 8080

CMD ["node" , "server" ]
 

Dans ce fichier, j'attends une instruction "VOLUME. / Usr / src / app" pour monter le contenu du répertoire de travail actuel de l'hôte sur le dossier / usr / src / app du conteneur.

S'il vous plaît laissez-moi savoir si c'est la bonne façon?

357voto

Martin Andersson Points 1869

En bref: Non, votre VOLUME instruction n'est pas correct.

Dockerfile de l' VOLUME spécifiez un ou plusieurs volumes de donnée contenant du côté des chemins. Mais il ne permet pas à l'image de l'auteur de spécifier un hôte chemin. Sur le côté hôte, les volumes sont créés avec un très long ID-nom à l'intérieur du Panneau de la racine. Sur ma machine, c'est - /var/lib/docker/volumes.

Remarque: en Raison de l'généré automatiquement le nom est très long et n'a pas de sens à partir d'un humain du point de vue, ces volumes sont souvent désignés comme des "sans nom" ou "anonyme".

Votre exemple qui utilise un caractère '.' aura même pas fonctionner sur ma machine, peu importe si je fais le point de la première ou de la deuxième argument. Je reçois ce message d'erreur:

docker: réponse d'Erreur de démon: bec erreur d'exécution: container_linux.aller:265: à partir conteneur processus a entraîné "process_linux.aller:368: conteneur init causé \"ouvrir /dev/ptmx: aucun fichier ou répertoire\"".

Je sais que ce qui a été dit à ce moment est probablement pas très utile à quelqu'un d'essayer de comprendre VOLUME et -v et il n'est certainement pas une solution pour ce que vous essayez d'accomplir. Alors, je l'espère, les exemples qui suivent vont faire la lumière sur ces questions.

Minitutorial: Spécification des volumes

Compte tenu de cette Dockerfile:

FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2

(Pour les résultats de cette minitutorial, il ne fait aucune différence si nous spécifier vol1 vol2 ou /vol1 /vol2 - ne me demandez pas pourquoi)

Construire:

docker build -t my-openjdk

Exécuter:

docker run --rm -it my-openjdk

À l'intérieur du conteneur, exécutez ls dans la ligne de commande et vous remarquerez deux répertoires existent; /vol1 et /vol2.

L'exécution du conteneur crée également deux répertoires, ou "volumes", sur le côté hôte.

Tout en ayant le conteneur 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 de ce nom avec les trois points pour des raisons 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 vide à l'emplacement).

Ce fichier est maintenant disponible sur la machine hôte, dans une de la sans nom volumes lol. Il m'a fallu deux essais car j'ai d'abord essayé le premier volume, mais finalement, j'ai trouvé mon fichier dans le deuxième volume répertoriés, à l'aide de 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 sera supprimée dans le conteneur.

Remarque: L' _data le dossier est également appelé "point de montage".

La sortie du récipient, et liste les volumes sur l'ordinateur hôte. Ils sont allés. Nous avons utilisé l' --rm drapeau lors de l'exécution du conteneur et cette option a pour effet de lingettes non seulement le récipient à la sortie, mais aussi les volumes.

Exécuter un nouveau conteneur, mais spécifier un volume à l'aide d' -v:

docker run --rm -it -v /vol3 my-openjdk

Cela ajoute un troisième volume et de l'ensemble du système finit par avoir trois sans nom volumes. La commande aurait écrasé l'on a spécifié qu' -v vol3. L'argument doit être un absolu chemin à l'intérieur du conteneur. Sur le côté hôte, le troisième volume est anonyme et réside avec les deux autres volumes en /var/lib/docker/volumes/.

Il a été indiqué plus tôt que l' Dockerfile peut ne pas correspondre à un hôte chemin qui sorte de poser un problème pour nous lorsque essayant de mettre des fichiers de l'hôte vers le réservoir en cours d'exécution. Un autre -v de la syntaxe permet de résoudre ce problème.

Imaginez que j'ai un sous-dossier de mon projet de répertoire ./src que je souhaite pour synchroniser /src à l'intérieur du conteneur. Cette commande fait l'affaire:

docker run -it -v $(pwd)/src:/src my-openjdk

Des deux côtés de l' : personnage s'attend à un chemin d'accès absolu. Côté gauche d'être un chemin d'accès absolu sur la machine hôte, côté droit d'être un chemin d'accès absolu à l'intérieur du conteneur. pwd est une commande qui "impression en cours/répertoire de travail". Mettre la commande dans l' $() prend le commandement à l'intérieur de la parenthèse, exécute un shell interne est exécuté et les rendements reprendre le chemin d'accès absolu à notre répertoire de projet.

Mettre tous 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 cette Dockerfile:

FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello

Nous exécutez cette commande:

docker run -v $(pwd)/src:/src my-openjdk

Cette affiche "Hello, World!".

La meilleure partie est que vous êtes totalement libre de modifier les .fichier java avec un nouveau message pour une autre sortie sur une deuxième exécution, sans avoir à reconstruire l'image =)

Remarques finales

Je suis assez nouveau dans le Panneau, et le fameux "tutoriel" reflète les informations que j'ai recueillies à partir de 3 jours de ligne de commande hackathon. Je suis presque honteux, je n'ai pas été en mesure de fournir des liens vers d'anglais clair-comme la documentation de la sauvegarde de mes déclarations, mais honnêtement, je pense que cela est dû à un manque de documentation et de ne pas l'effort personnel. Je sais que les exemples fonctionnent comme annoncé à l'aide de mon installation actuelle qui est "Windows 10 -> Vagrant 2.0.0 -> menu fixe 17.09.0-ce".

Le tutoriel n'est pas de résoudre le problème de "comment pouvons-nous préciser le conteneur du chemin d'accès dans le Dockerfile et laisser la course de commande de ne spécifier l'hôte chemin". Il y a peut être une façon, je n'en ai pas trouvé.

Enfin, j'ai le pressentiment que la spécification VOLUME dans le Dockerfile n'est pas seulement rare, mais c'est probablement la meilleure pratique consiste à ne jamais utiliser d' VOLUME. Et ce pour deux raisons. La première raison que nous avons déjà identifiés: Nous ne pouvons pas spécifier l'hôte chemin - ce qui est une bonne chose, parce que les Dockerfiles devrait être très agnostique aux spécificités d'une machine hôte. Mais la deuxième raison est que les gens peuvent oublier d'utiliser le --rm option lors de l'exécution du conteneur. On pourrait n'oubliez pas de retirer le récipient, mais oublier de supprimer le volume. De Plus, même avec le meilleur de la mémoire humaine, il pourrait être une tâche ardue pour savoir qui de toutes anonymes, les volumes sont sans danger pour le retirer.

145voto

Bukharov Sergey Points 3831

Officiel docker tutoriel dit:

Un volume de données est un spécialement désigné répertoire dans un ou plusieurs récipients qui contourne l'Union de Système de Fichiers. Les volumes de données offrent plusieurs fonctionnalités utiles pour persistantes ou de données partagée:

  • Les Volumes sont initialisés lorsqu'un conteneur est créé. Si le conteneur de l'image de base contient des données au point de montage spécifié,
    que les données sont copiées dans le nouveau volume sur volume
    l'initialisation. (Notez que cela ne s'applique pas en cas de montage d'un hôte
    répertoire.)
  • Volumes de données peuvent être partagées et réutilisées entre les conteneurs.

  • Les modifications apportées à un volume de données sont effectués directement.

  • Les modifications apportées à un volume de données ne seront pas inclus lorsque vous mettez à jour une image.

  • Les volumes de données persistent même si le conteneur lui-même est supprimé.

En Dockerfile vous pouvez uniquement spécifier la destination de volume à l'intérieur du conteneur. par exemple, /usr/src/app.

Lorsque vous exécutez le conteneur par exemple, docker run --volume=/opt:/usr/src/app my_image vous pouvez , mais pas nécessaire de spécifier le point de montage (/opt) dans la machine hôte. Si vous ne spécifiez pas --volume argument alors le point de montage sera choisi automatiquement

46voto

mr haven Points 136

L' VOLUME commande dans un Dockerfile est tout à fait légitime, totalement classique, absolument parfait à utiliser et il n'est pas obsolète de toute façon. Juste besoin de le comprendre.

Nous l'utilisons pour pointer vers les répertoires de l'application dans le conteneur va écrire beaucoup. Nous n'utilisons pas d' VOLUME juste parce que nous voulons partager entre l'hôte et le récipient comme un fichier de config.

La commande a simplement besoin d'un param; un chemin d'accès à un dossier, par rapport à l' WORKDIR si elle est définie, à partir de l'intérieur du conteneur. Puis docker va créer un volume dans son graphique(/var/lib/menu fixe) et monter le dossier dans le conteneur. Maintenant, le conteneur va avoir un endroit pour écrire avec la haute performance. Sans l' VOLUME commande de la vitesse d'écriture dans le dossier spécifié sera très lent, parce que maintenant le conteneur est l'utilisation de l' copy on write stratégie dans le conteneur lui-même. L' copy on write stratégie est une des principales raisons pourquoi il existe des volumes.

Si vous montez sur le dossier spécifié par l' VOLUME de commande, la commande n'est pas exécutée car VOLUME n'est exécuté que lorsque le conteneur commence, un peu comme ENV.

Fondamentalement, avec VOLUME commande vous obtenez des performances sans en externe montage de tous les volumes. Données permettra d'économiser à travers le conteneur s'exécute sans aucune externes supports. Puis, une fois prêt il suffit de monter quelque chose sur elle.

Quelques bon exemple de cas d'utilisation:
- les journaux
- dossiers temp

Quelques mauvais cas d'utilisation:
- les fichiers statiques
- configs
- code

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X