Comment monter des volumes hôtes dans des conteneurs Docker dans Dockerfile pendant la génération

Question originale: Comment utiliser l’instruction VOLUME dans Dockerfile?

Révisé: mise à jour à partir de la réponse ci-dessous, la question que je veux résoudre est la suivante: comment monter des volumes hôtes dans des conteneurs Dockerfile lors de la construction, c.-à-d.

Dernière mise à jour: Il existe une solution maintenant. Bien que ce ne soit pas ssortingctement Docker, mais ” cela résout tous les points faibles de Dockerfile “, je pense que c’est la réponse parfaite. Consultez ma dernière réponse pour plus de détails.

Mise à jour: La réponse est donc “Pas possible”. Je peux l’accepter comme une réponse car je sais que le problème a été largement discuté à https://github.com/docker/docker/issues/3156 . Je peux comprendre que la portabilité est une question primordiale pour le développeur de docker; mais en tant qu’utilisateur de docker, je dois dire que je suis très déçu de cette fonctionnalité manquante. Permettez-moi de clore mon argument par une citation tirée de la discussion susmentionnée: ” Je voudrais utiliser Gentoo comme image de base, mais je ne veux certainement pas que> 1 Go de données d’arborescence Portage se trouvent dans les couches une fois l’image créée.” pourrait avoir de jolis contenants compacts si l’arborescence de portage gigantesque ne devait pas apparaître dans l’image pendant l’installation. “Oui, je peux utiliser wget ou curl pour télécharger tout ce dont j’ai besoin, mais le simple fait me force maintenant à télécharger> 1 Go d’arbre Portage chaque fois que je construis une image de base Gentoo n’est ni efficace ni conviviale. De plus, le référentiel de paquets sera TOUJOURS sous / usr / portage, donc TOUJOURS PORTABLE sous Gentoo. Encore une fois, je respecte la décision, mais permettez-moi d’exprimer ma déception aussi dans l’intervalle. Merci.

Question originale en détail:

De

Partage de répertoires via des volumes
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

il indique que la fonctionnalité de volumes de données “est disponible depuis la version 1 de l’API Docker Remote”. Mon menu fixe est de la version 1.2.0, mais je trouve que l’exemple donné dans l’article ci-dessus ne fonctionne pas:

 # BUILD-USING:        docker build -t data . # RUN-USING:          docker run -name DATA data FROM          busybox VOLUME        ["/var/volume1", "/var/volume2"] CMD           ["/usr/bin/true"] 

Quelle est la manière appropriée dans Dockerfile de monter des volumes montés sur l’hôte dans des conteneurs Docker, via la commande VOLUME?

 $ apt-cache policy lxc-docker lxc-docker: Installed: 1.2.0 Candidate: 1.2.0 Version table: *** 1.2.0 0 500 https://get.docker.io/ubuntu/ docker/main amd64 Packages 100 /var/lib/dpkg/status $ cat Dockerfile FROM debian:sid VOLUME ["/export"] RUN ls -l /export CMD ls -l /export $ docker build -t data . Sending build context to Docker daemon 2.56 kB Sending build context to Docker daemon Step 0 : FROM debian:sid ---> 77e97a48ce6a Step 1 : VOLUME ["/export"] ---> Using cache ---> 59b69b65a074 Step 2 : RUN ls -l /export ---> Running in df43c78d74be total 0 ---> 9d29a6eb263f Removing intermediate container df43c78d74be Step 3 : CMD ls -l /export ---> Running in 8e4916d3e390 ---> d6e7e1c52551 Removing intermediate container 8e4916d3e390 Successfully built d6e7e1c52551 $ docker run data total 0 $ ls -l /export | wc 20 162 1131 $ docker -v Docker version 1.2.0, build fa7b24f 

Il n’est pas possible d’utiliser l’instruction VOLUME pour indiquer à docker quoi monter. Cela porterait gravement atteinte à la portabilité. Cette instruction indique à docker que le contenu de ces répertoires ne va pas dans les images et peut être accédé à partir d’autres conteneurs à l’aide du --volumes-from ligne --volumes-from commande --volumes-from . Vous devez exécuter le conteneur en utilisant -v /path/on/host:/path/in/container pour accéder aux répertoires de l’hôte.

Le assembly de volumes hôtes lors de la construction n’est pas possible. Il n’y a pas de construction privilégiée et le assembly de l’hôte dégraderait sérieusement la portabilité. Vous pouvez essayer d’utiliser wget ou curl pour télécharger tout ce dont vous avez besoin pour la construction et le mettre en place.

MISE À JOUR: Quelqu’un ne refusera tout simplement pas la réponse, et je l’aime beaucoup, en particulier pour cette question particulière.

BONNES NOUVELLES, il y a un moyen maintenant –

La solution est Rocker: https://github.com/grammarly/rocker

John Yani a déclaré : “À l’OMI, cela résout tous les points faibles de Dockerfile, ce qui la rend adaptée au développement.”

Bascule

https://github.com/grammarly/rocker

En introduisant de nouvelles commandes, Rocker vise à résoudre les cas d’utilisation suivants, qui sont douloureux avec Docker ordinaire:

  1. Montez des volumes réutilisables à l’étape de la génération afin que les outils de gestion des dépendances utilisent le cache entre les versions.
  2. Partagez les clés ssh avec build (pour extraire les repos privés, etc.), sans les laisser dans l’image résultante.
  3. Construire et exécuter une application dans différentes images, être capable de transmettre facilement un artefact d’une image à une autre, idéalement avoir cette logique dans un seul fichier Dockerfile.
  4. Tag / Push images directement à partir de Dockerfiles.
  5. Passez les variables de la commande de construction du shell afin qu’elles puissent être substituées à un fichier Docker.

Et plus. Ce sont les problèmes les plus critiques qui bloquaient notre adoption de Docker à Grammarly.

Il existe un moyen de monter un volume pendant une construction, mais cela ne concerne pas les fichiers Docker.

La technique serait de créer un conteneur à partir de la base que vous souhaitez utiliser (monter votre volume dans le conteneur avec l’option -v ), exécuter un script shell pour effectuer votre travail de création d’image, puis valider le conteneur en tant qu’image. lorsque vous avez terminé.

Non seulement cela laissera de côté les fichiers inutiles que vous ne voulez pas (ceci est également utile pour les fichiers sécurisés, comme les fichiers SSH), mais il crée également une seule image. Il a des inconvénients: la commande commit ne prend pas en charge toutes les instructions de Dockerfile, et elle ne vous permet pas de reprendre lorsque vous avez dû éditer votre script de compilation.

Lorsque vous exécutez le conteneur, un répertoire sur votre hôte est créé et monté dans le conteneur. Vous pouvez trouver quel répertoire c’est avec

 $ docker inspect --format "{{ .Volumes }}"  map[/export:/var/lib/docker/vfs/dir/] 

Si vous souhaitez monter un répertoire à partir de votre hôte dans votre conteneur, vous devez utiliser le paramètre -v et spécifier le répertoire. Dans votre cas, ce serait:

 docker run -v /export:/export data 

Donc, vous utiliseriez le dossier hosts dans votre conteneur.

Je pense que vous pouvez faire ce que vous voulez en exécutant la construction via une commande docker qui est elle-même exécutée dans un conteneur Docker. Voir Docker peut maintenant fonctionner dans Docker | Docker Blog . Une technique comme celle-ci, mais qui a réellement accédé au docker externe à partir d’un conteneur, a été utilisée, par exemple, tout en explorant comment créer le plus petit conteneur Docker possible | Blog Xebia .

Un autre article pertinent est l’ optimisation des images de Docker | CenturyLink Labs , qui explique que si vous téléchargez des fichiers pendant une construction, vous pouvez éviter de gaspiller de l’espace dans l’image finale en téléchargeant, en construisant et en supprimant le téléchargement en une seule étape.

C’est moche, mais j’ai réalisé un semblant de ça comme ça:

Dockerfile:

 FROM foo COPY ./m2/ /root/.m2 RUN stuff 

imageBuild.sh:

 docker build . -t barImage container="$(docker run -d barImage)" rm -rf ./m2 docker cp "$container:/root/.m2" ./m2 docker rm -f "$container" 

J’ai une version java qui télécharge l’univers dans /root/.m2 et l’a fait à chaque fois . imageBuild.sh copie le contenu de ce dossier sur l’hôte après la construction et Dockerfile recopie dans l’image pour la génération suivante.

C’est quelque chose comme comment un volume fonctionnerait (c’est-à-dire qu’il persiste entre les builds).